1
0
mirror of https://github.com/djhackersdev/bemanitools.git synced 2024-11-12 01:10:49 +01:00

aciomgr: Add acio manager dll

This commit is contained in:
Will Xyen 2021-03-09 22:50:00 -08:00 committed by b775d4b79856d2b538f34c4bd2ef68af9d144fff
parent a4436747de
commit 089253a537
15 changed files with 457 additions and 38 deletions

View File

@ -78,6 +78,7 @@ imps += avs avs-ea3
include src/main/aciodrv/Module.mk
include src/main/acioemu/Module.mk
include src/main/aciomgr/Module.mk
include src/main/aciotest/Module.mk
include src/main/asio/Module.mk
include src/main/bio2drv/Module.mk
@ -378,6 +379,7 @@ $(zipdir)/iidx-27.zip: \
$(V)zip -j $@ $^
$(zipdir)/iidx-hwio-x86.zip: \
build/bin/indep-32/aciomgr.dll \
build/bin/indep-32/eamio-icca.dll \
build/bin/indep-32/iidxio-bio2.dll \
build/bin/indep-32/iidxio-ezusb.dll \
@ -390,6 +392,7 @@ $(zipdir)/iidx-hwio-x86.zip: \
$(V)zip -j $@ $^
$(zipdir)/iidx-hwio-x64.zip: \
build/bin/indep-64/aciomgr.dll \
build/bin/indep-64/eamio-icca.dll \
build/bin/indep-64/iidxio-bio2.dll \
build/bin/indep-64/iidxio-ezusb.dll \
@ -483,6 +486,8 @@ $(zipdir)/sdvx-05-cn.zip: \
$(V)zip -j $@ $^
$(zipdir)/sdvx-hwio-x86.zip: \
build/bin/indep-32/aciomgr.dll \
build/bin/indep-32/eamio-icca.dll \
build/bin/indep-32/sdvxio-kfca.dll \
build/bin/indep-32/sdvxio-bio2.dll \
build/bin/indep-32/vigem-sdvxio.exe \
@ -491,6 +496,8 @@ $(zipdir)/sdvx-hwio-x86.zip: \
$(V)zip -j $@ $^
$(zipdir)/sdvx-hwio-x64.zip: \
build/bin/indep-64/aciomgr.dll \
build/bin/indep-64/eamio-icca.dll \
build/bin/indep-64/sdvxio-kfca.dll \
build/bin/indep-64/sdvxio-bio2.dll \
build/bin/indep-64/vigem-sdvxio.exe \

View File

@ -291,7 +291,13 @@ static bool aciodrv_device_start_node(struct aciodrv_device_ctx *device, uint8_t
return true;
}
// deprecated name
struct aciodrv_device_ctx *aciodrv_device_open(const char *port_path, int baud)
{
return aciodrv_device_open_path(port_path, baud);
}
struct aciodrv_device_ctx *aciodrv_device_open_path(const char *port_path, int baud)
{
HANDLE port = aciodrv_port_open(port_path, baud);

View File

@ -18,7 +18,13 @@ struct aciodrv_device_ctx;
* @param baud Baud rate for communication (e.g. 57600 for ICCA)
* @return opened device context, NULL on error
*/
struct aciodrv_device_ctx *aciodrv_device_open(const char *port_path, int baud);
struct aciodrv_device_ctx *aciodrv_device_open(const char *port_path, int baud)
#ifdef __GNUC__
__attribute__((deprecated("Use aciomgr instead if device is shareable, else aciodrv_device_open_path")))
#endif
;
struct aciodrv_device_ctx *aciodrv_device_open_path(const char *port_path, int baud);
/**
* Get the node count on the opened device.

View File

@ -0,0 +1,8 @@
dlls += aciomgr
libs_aciomgr := \
aciodrv \
util \
src_aciomgr := \
manager.c \

View File

@ -0,0 +1,12 @@
LIBRARY aciomgr
EXPORTS
aciomgr_set_loggers
aciomgr_port_init
aciomgr_port_fini
aciomgr_get_node_count
aciomgr_get_node_product_ident
aciomgr_port_submit_packet
aciomgr_port_checkout
aciomgr_port_checkin
DllMain@12 @1 NONAME

201
src/main/aciomgr/manager.c Normal file
View File

@ -0,0 +1,201 @@
#define LOG_MODULE "aciomgr-manager"
#include <windows.h>
#include <stdatomic.h>
#include "manager.h"
#include "aciodrv/device.h"
#include "util/array.h"
#include "util/log.h"
#define MAX_PORT_PATH_LENGTH 256
struct aciomgr_port_dispatcher {
CRITICAL_SECTION cs;
size_t references;
struct aciodrv_device_ctx *device;
char path[MAX_PORT_PATH_LENGTH];
int baud;
};
static void _aciomgr_setup_port_dispatcher(
struct aciomgr_port_dispatcher *dispatcher, const char *path, int baud);
static void _aciomgr_destroy_port_dispatcher(
struct aciomgr_port_dispatcher *dispatcher);
static void _aciomgr_init();
static void _aciomgr_fini();
// DLL-globals
static atomic_bool running;
static CRITICAL_SECTION mgr_cs;
static struct array active_ports;
static void _aciomgr_setup_port_dispatcher(
struct aciomgr_port_dispatcher *dispatcher, const char *path, int baud)
{
InitializeCriticalSection(&dispatcher->cs);
strcpy(dispatcher->path, path);
dispatcher->baud = baud;
dispatcher->device = aciodrv_device_open_path(path, baud);
dispatcher->references = 0;
}
static void _aciomgr_destroy_port_dispatcher(
struct aciomgr_port_dispatcher *dispatcher)
{
aciodrv_device_close(dispatcher->device);
DeleteCriticalSection(&dispatcher->cs);
}
static void _aciomgr_init()
{
if (running) {
// warn
_aciomgr_fini();
}
InitializeCriticalSection(&mgr_cs);
array_init(&active_ports);
running = true;
}
static void _aciomgr_fini()
{
if (!running) {
// warn
}
running = false;
DeleteCriticalSection(&mgr_cs);
array_fini(&active_ports);
}
void aciomgr_set_loggers(
log_formatter_t misc,
log_formatter_t info,
log_formatter_t warning,
log_formatter_t fatal)
{
log_to_external(misc, info, warning, fatal);
}
struct aciomgr_port_dispatcher *aciomgr_port_init(const char *path, int baud)
{
if (!running) {
// warn
return NULL;
}
if (strlen(path) >= MAX_PORT_PATH_LENGTH) {
// warn
return NULL;
}
struct aciomgr_port_dispatcher* entry;
EnterCriticalSection(&mgr_cs);
for (size_t i = 0; i < active_ports.nitems; i++) {
entry = array_item(struct aciomgr_port_dispatcher, &active_ports, i);
if (strcmp(entry->path, path) == 0) {
// found
if (entry->baud != baud) {
log_warning(
"Device at %s opened with baud of %d, but requested %d",
path,
entry->baud,
baud);
}
goto done;
}
}
entry = array_append(struct aciomgr_port_dispatcher, &active_ports);
_aciomgr_setup_port_dispatcher(entry, path, baud);
done:
entry->references++;
LeaveCriticalSection(&mgr_cs);
return entry;
}
void aciomgr_port_fini(struct aciomgr_port_dispatcher *dispatcher)
{
if (!running) {
// warn
return;
}
EnterCriticalSection(&mgr_cs);
dispatcher->references--;
LeaveCriticalSection(&mgr_cs);
if (dispatcher->references == 0) {
_aciomgr_destroy_port_dispatcher(dispatcher);
}
}
// this function don't require the lock
uint8_t aciomgr_get_node_count(struct aciomgr_port_dispatcher *dispatcher) {
return aciodrv_device_get_node_count(dispatcher->device);
}
// this function don't require the lock
bool aciomgr_get_node_product_ident(
struct aciomgr_port_dispatcher *dispatcher,
uint8_t node_id,
char product[4])
{
return aciodrv_device_get_node_product_ident(dispatcher->device, node_id, product);
}
bool aciomgr_port_submit_packet(
struct aciomgr_port_dispatcher *dispatcher,
struct ac_io_message *msg,
int max_resp_size)
{
// CS's although lightweight, may still be a burden, short circuit
if (dispatcher->references > 1) {
EnterCriticalSection(&dispatcher->cs);
bool response = aciodrv_send_and_recv(dispatcher->device, msg, max_resp_size);
LeaveCriticalSection(&dispatcher->cs);
return response;
}
return aciodrv_send_and_recv(dispatcher->device, msg, max_resp_size);
}
struct aciodrv_device_ctx *aciomgr_port_checkout(
struct aciomgr_port_dispatcher *dispatcher)
{
if (dispatcher->references > 1) {
EnterCriticalSection(&dispatcher->cs);
}
return dispatcher->device;
}
void aciomgr_port_checkin(struct aciomgr_port_dispatcher *dispatcher) {
if (dispatcher->references > 1) {
LeaveCriticalSection(&dispatcher->cs);
}
}
BOOL WINAPI DllMain(HMODULE self, DWORD reason, void *ctx)
{
if (reason == DLL_PROCESS_ATTACH) {
_aciomgr_init();
}
if (reason == DLL_PROCESS_DETACH) {
_aciomgr_fini();
}
return TRUE;
}

View File

@ -0,0 +1,82 @@
#ifndef ACIOMGR_MANAGER_H
#define ACIOMGR_MANAGER_H
#include <stdbool.h>
#include "acio/acio.h"
#include "bemanitools/glue.h"
struct aciodrv_device_ctx;
struct aciomgr_port_dispatcher;
/**
* The first function that will be called on your DLL. You will be supplied
* with four function pointers that may be used to log messages to the game's
* log file. See comments in glue.h for further information.
*/
void aciomgr_set_loggers(
log_formatter_t misc,
log_formatter_t info,
log_formatter_t warning,
log_formatter_t fatal);
/**
* Init and open, or return the existing handle to an acio port
*
* @param path Port the device is connected to (e.g. "COM1")
* @return opened port dispatcher context, NULL on error
*/
struct aciomgr_port_dispatcher *aciomgr_port_init(const char *path, int baud);
void aciomgr_port_fini(struct aciomgr_port_dispatcher *dispatcher);
/**
* Get the node count on the opened device.
*
* @param dispatcher dispatcher context from aciomgr_port_init
* @return Total num of nodes enumerated on the ACIO device.
*/
uint8_t aciomgr_get_node_count(struct aciomgr_port_dispatcher *dispatcher);
/**
* Get the product identifier of an enumerated node.
*
* @param dispatcher dispatcher context from aciomgr_port_init
* @param node_id Id of the node. Needs to be in range of the total node count.
* @param product Buffer to return the product id to.
* @return True on success, false on error. If True the variable product
* contains the identifier of the queried node.
*/
bool aciomgr_get_node_product_ident(struct aciomgr_port_dispatcher *dispatcher, uint8_t node_id, char product[4]);
/**
* Submit and wait for the response of the specified packet
*
* @param dispatcher dispatcher context from aciomgr_port_init
* @param msg pointer to the message buffer to read from / write to
* @param max_resp_size pointer to the max size response we expect
* @return false on error
*/
bool aciomgr_port_submit_packet(
struct aciomgr_port_dispatcher *dispatcher,
struct ac_io_message *msg,
int max_resp_size);
/**
* Checkout the device handler for this port dispatcher on this thread
*
* @param dispatcher dispatcher context from aciomgr_port_init
* @return the device context
*/
struct aciodrv_device_ctx *aciomgr_port_checkout(
struct aciomgr_port_dispatcher *dispatcher);
/**
* Checkin the device handler that this thread holds
*
* @param dispatcher dispatcher context from aciomgr_port_init
*/
void aciomgr_port_checkin(struct aciomgr_port_dispatcher *dispatcher);
#endif

View File

@ -71,7 +71,7 @@ int main(int argc, char **argv)
log_to_writer(log_writer_stdout, NULL);
struct aciodrv_device_ctx *device = aciodrv_device_open(argv[1], atoi(argv[2]));
struct aciodrv_device_ctx *device = aciodrv_device_open_path(argv[1], atoi(argv[2]));
if (!device) {
printf("Opening acio device failed\n");

View File

@ -110,7 +110,7 @@ bool bio2drv_bi2a_iidx_poll(
device,
&msg,
offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
log_warning("[%x] Polling of node %d failed", node_id + 1);
log_warning("Polling of node %d failed", node_id + 1);
return false;
}

View File

@ -3,6 +3,7 @@ dlls += \
libs_eamio-icca := \
aciodrv \
aciomgr \
util \
src_eamio-icca := \

View File

@ -8,13 +8,15 @@
#include <stdint.h>
#include <stdio.h>
#include "aciodrv/device.h"
#include "aciomgr/manager.h"
#include "aciodrv/icca.h"
#include "bemanitools/eamio.h"
#include "util/log.h"
#define NUMBER_OF_EMULATED_READERS 2
static const uint8_t eam_io_keypad_mappings[16] = {EAM_IO_KEYPAD_DECIMAL,
EAM_IO_KEYPAD_3,
EAM_IO_KEYPAD_6,
@ -32,9 +34,11 @@ static const uint8_t eam_io_keypad_mappings[16] = {EAM_IO_KEYPAD_DECIMAL,
EAM_IO_KEYPAD_5,
EAM_IO_KEYPAD_8};
static struct ac_io_icca_state eam_io_icca_state[2];
static struct ac_io_icca_state eam_io_icca_state[NUMBER_OF_EMULATED_READERS];
static struct aciodrv_device_ctx *acio_device_ctx;
static struct aciomgr_port_dispatcher *acio_manager_ctx;
static int32_t icca_node_id[NUMBER_OF_EMULATED_READERS];
void eam_io_set_loggers(
log_formatter_t misc,
@ -42,32 +46,83 @@ void eam_io_set_loggers(
log_formatter_t warning,
log_formatter_t fatal)
{
/* Pass logger functions on to aciomgr so that it has somewhere to write
its own log output. */
aciomgr_set_loggers(misc, info, warning, fatal);
log_to_external(misc, info, warning, fatal);
}
static bool check_if_icca(int node_id) {
char product[4];
aciomgr_get_node_product_ident(acio_manager_ctx, node_id, product);
if (!memcmp(product, "ICCA", 4)) {
return true;
}
if (!memcmp(product, "ICCB", 4)) {
return true;
}
if (!memcmp(product, "ICCC", 4)) {
return true;
}
return false;
}
bool eam_io_init(
thread_create_t create, thread_join_t join, thread_destroy_t destroy)
{
acio_device_ctx = aciodrv_device_open("COM1", 57600);
acio_manager_ctx = aciomgr_port_init("COM1", 57600);
if (acio_device_ctx == NULL) {
if (acio_manager_ctx == NULL) {
log_warning("Opening acio device on COM1 failed");
return false;
}
for (uint8_t i = 0; i < 2; i++) {
if (!aciodrv_icca_init(acio_device_ctx, i)) {
log_warning("Initializing icca %d failed", i);
return false;
struct aciodrv_device_ctx *device = aciomgr_port_checkout(acio_manager_ctx);
for (uint8_t i = 0; i < NUMBER_OF_EMULATED_READERS; i++) {
icca_node_id[i] = -1;
for (uint8_t nid = 0; nid < aciomgr_get_node_count(acio_manager_ctx); ++nid) {
if (check_if_icca(nid)) {
bool existing_reader = false;
for (uint8_t j = 0; j < i; j++) {
if (nid == icca_node_id[j]) {
existing_reader = true;
break;
}
}
if (existing_reader) {
continue;
}
icca_node_id[i] = nid;
if (!aciodrv_icca_init(device, icca_node_id[i])) {
log_warning("Initializing icca %d failed", i);
// if we have at least 1 valid reader, don't fail
// (ex: for games that expect only 1 reader)
if (i > 0) {
aciomgr_port_checkin(acio_manager_ctx);
return false;
}
}
break;
}
}
}
aciomgr_port_checkin(acio_manager_ctx);
return true;
}
void eam_io_fini(void)
{
aciodrv_device_close(acio_device_ctx);
aciomgr_port_fini(acio_manager_ctx);
}
uint16_t eam_io_get_keypad_state(uint8_t unit_no)
@ -113,35 +168,54 @@ uint8_t eam_io_read_card(uint8_t unit_no, uint8_t *card_id, uint8_t nbytes)
bool eam_io_card_slot_cmd(uint8_t unit_no, uint8_t cmd)
{
// this node is not setup, just return "success""
if (icca_node_id[unit_no] == -1) {
return true;
}
struct aciodrv_device_ctx *device = aciomgr_port_checkout(acio_manager_ctx);
bool response = false;
switch (cmd) {
case EAM_IO_CARD_SLOT_CMD_CLOSE:
return aciodrv_icca_set_state(
acio_device_ctx, unit_no, AC_IO_ICCA_SLOT_STATE_CLOSE, NULL);
response = aciodrv_icca_set_state(
device, unit_no, AC_IO_ICCA_SLOT_STATE_CLOSE, NULL);
case EAM_IO_CARD_SLOT_CMD_OPEN:
return aciodrv_icca_set_state(
acio_device_ctx, unit_no, AC_IO_ICCA_SLOT_STATE_OPEN, NULL);
response = aciodrv_icca_set_state(
device, unit_no, AC_IO_ICCA_SLOT_STATE_OPEN, NULL);
case EAM_IO_CARD_SLOT_CMD_EJECT:
return aciodrv_icca_set_state(
acio_device_ctx, unit_no, AC_IO_ICCA_SLOT_STATE_EJECT, NULL);
response = aciodrv_icca_set_state(
device, unit_no, AC_IO_ICCA_SLOT_STATE_EJECT, NULL);
case EAM_IO_CARD_SLOT_CMD_READ:
return aciodrv_icca_read_card(acio_device_ctx, unit_no, NULL) &&
response = aciodrv_icca_read_card(device, unit_no, NULL) &&
aciodrv_icca_get_state(
acio_device_ctx, unit_no, &eam_io_icca_state[unit_no]);
device, unit_no, &eam_io_icca_state[unit_no]);
default:
break;
}
aciomgr_port_checkin(acio_manager_ctx);
return false;
return response;
}
bool eam_io_poll(uint8_t unit_no)
{
return aciodrv_icca_get_state(
acio_device_ctx, unit_no, &eam_io_icca_state[unit_no]);
// this node is not setup, just return "success""
if (icca_node_id[unit_no] == -1) {
return true;
}
bool response = aciodrv_icca_get_state(
aciomgr_port_checkout(acio_manager_ctx),
unit_no,
&eam_io_icca_state[unit_no]);
aciomgr_port_checkin(acio_manager_ctx);
return response;
}
const struct eam_io_config_api *eam_io_get_config_api(void)

View File

@ -116,7 +116,8 @@ bool iidx_io_init(
}
}
bio2_device_ctx = aciodrv_device_open(selected_port, config_bio2.baud);
// BIO2's cannot share a bus with anything else, so use device directly
bio2_device_ctx = aciodrv_device_open_path(selected_port, config_bio2.baud);
if (bio2_device_ctx == NULL) {
log_info("Opening BIO2 device on [%s] failed", selected_port);

View File

@ -101,7 +101,8 @@ bool sdvx_io_init(
}
}
bio2_device_ctx = aciodrv_device_open(selected_port, config_bio2.baud);
// BIO2's cannot share a bus with anything else, so use device directly
bio2_device_ctx = aciodrv_device_open_path(selected_port, config_bio2.baud);
if (bio2_device_ctx == NULL) {
log_info("Opening BIO2 device on [%s] failed", selected_port);

View File

@ -3,6 +3,7 @@ dlls += sdvxio-kfca
libs_sdvxio-kfca := \
geninput \
aciodrv \
aciomgr \
cconfig \
util \

View File

@ -9,7 +9,7 @@
#include "cconfig/cconfig-main.h"
#include "aciodrv/device.h"
#include "aciomgr/manager.h"
#include "aciodrv/kfca.h"
#include "sdvxio-kfca/config-kfca.h"
@ -37,7 +37,7 @@ static int16_t kfca_node_id;
struct ac_io_kfca_poll_out pout_staging;
struct ac_io_kfca_poll_out pout_ready;
static struct aciodrv_device_ctx *acio_device_ctx;
static struct aciomgr_port_dispatcher *acio_manager_ctx;
void sdvx_io_set_loggers(
log_formatter_t misc,
@ -45,6 +45,10 @@ void sdvx_io_set_loggers(
log_formatter_t warning,
log_formatter_t fatal)
{
/* Pass logger functions on to aciomgr so that it has somewhere to write
its own log output. */
aciomgr_set_loggers(misc, info, warning, fatal);
sdvx_io_log_misc = misc;
sdvx_io_log_info = info;
sdvx_io_log_warning = warning;
@ -80,23 +84,23 @@ bool sdvx_io_init(
cconfig_finit(config);
acio_device_ctx = aciodrv_device_open(config_kfca.port, config_kfca.baud);
acio_manager_ctx = aciomgr_port_init(config_kfca.port, config_kfca.baud);
if (acio_device_ctx == NULL) {
if (acio_manager_ctx == NULL) {
log_info("Opening acio device on [%s] failed", config_kfca.port);
return 0;
}
log_info("Opening acio device successful");
uint8_t node_count = aciodrv_device_get_node_count(acio_device_ctx);
uint8_t node_count = aciomgr_get_node_count(acio_manager_ctx);
log_info("Enumerated %d nodes", node_count);
kfca_node_id = -1;
for (uint8_t i = 0; i < node_count; i++) {
char product[4];
aciodrv_device_get_node_product_ident(acio_device_ctx, i, product);
aciomgr_get_node_product_ident(acio_manager_ctx, i, product);
log_info(
"> %d: %c%c%c%c\n",
i,
@ -116,7 +120,12 @@ bool sdvx_io_init(
if (kfca_node_id != -1) {
log_warning("Using KFCA on node: %d", kfca_node_id);
if (!aciodrv_kfca_init(acio_device_ctx, kfca_node_id)) {
bool init_result = aciodrv_kfca_init(
aciomgr_port_checkout(acio_manager_ctx),
kfca_node_id);
aciomgr_port_checkin(acio_manager_ctx);
if (!init_result) {
log_warning("Unable to start KFCA on node: %d", kfca_node_id);
return false;
}
@ -167,7 +176,14 @@ bool sdvx_io_read_input(void)
}
processing_io = true;
if (!aciodrv_kfca_poll(acio_device_ctx, kfca_node_id, &pout_ready, &pin)) {
bool poll_result = aciodrv_kfca_poll(
aciomgr_port_checkout(acio_manager_ctx),
kfca_node_id,
&pout_ready,
&pin);
aciomgr_port_checkin(acio_manager_ctx);
if (!poll_result) {
return false;
}
@ -221,10 +237,13 @@ bool sdvx_io_set_amp_volume(
return false;
}
if (!aciodrv_kfca_amp(
acio_device_ctx,
kfca_node_id,
primary, 96, headphone, subwoofer)) {
bool amp_result = aciodrv_kfca_amp(
aciomgr_port_checkout(acio_manager_ctx),
kfca_node_id,
primary, 96, headphone, subwoofer);
aciomgr_port_checkin(acio_manager_ctx);
if (!amp_result) {
return false;
}