mirror of
https://github.com/pumpitupdev/pumptools.git
synced 2024-11-24 07:00:09 +01:00
patch/piuio: Re-write emulation layer, usb_ctrl -> piuio API
Aside not being well written code, it did not consider that the pumptools's piuio API is abstracting any kind of sensor multiplexing to hardware. With the game still calling the libusb API like usual, which is 8 calls (4 ins and 4 outs) for a single IO state update, this layer issued 4 times as many calls to any pumptools piuio API implementation. When using the piuio-real wrapper impl. this means that the real IO hardware was polled 4 times as often as the game actually intended to do. That might have also lead to rather high CPU load on older hardware, e.g. stock MK6/9 builds.
This commit is contained in:
parent
956a322013
commit
7f1a0b075b
@ -14,6 +14,10 @@
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
// Enable this to get a detailed "call trace" of reads/writes and updates
|
||||
// for debugging purpose
|
||||
// #define PATCH_PIUIO_CALL_TRACE
|
||||
|
||||
static bool _patch_piuio_enumerate(bool real_exists);
|
||||
static enum cnh_result _patch_piuio_open(void);
|
||||
static enum cnh_result _patch_piuio_reset(void);
|
||||
@ -21,8 +25,9 @@ static enum cnh_result _patch_piuio_control_msg(int request_type, int request, i
|
||||
struct cnh_iobuf* buffer, int timeout);
|
||||
static void _patch_piuio_close(void);
|
||||
|
||||
static enum cnh_result _patch_piuio_process_inputs(struct cnh_iobuf* buffer);
|
||||
static enum cnh_result _patch_piuio_process_outputs(struct cnh_iobuf* buffer);
|
||||
static void _patch_piuio_read_inputs_to_buffer(struct cnh_iobuf* buffer);
|
||||
static void _patch_piuio_read_outputs_from_buffer(struct cnh_iobuf* buffer);
|
||||
static enum ptapi_io_piuio_sensor_group _patch_piuio_get_sensor_group_from_buffer(struct cnh_iobuf* buffer);
|
||||
|
||||
static const struct cnh_usb_emu_virtdev_ep _patch_piuio_virtdev = {
|
||||
.pid = PIUIO_DRV_PID,
|
||||
@ -101,20 +106,73 @@ static enum cnh_result _patch_piuio_reset(void)
|
||||
static enum cnh_result _patch_piuio_control_msg(int request_type, int request, int value, int index,
|
||||
struct cnh_iobuf* buffer, int timeout)
|
||||
{
|
||||
/**
|
||||
* Expected call pattern for a full game state update on a single frame (when done synchronously)
|
||||
*
|
||||
* CTRL_OUT: light data + sensor 0
|
||||
* CTRL_IN: input data of sensor 0
|
||||
* CTRL_OUT: light data + sensor 1
|
||||
* CTRL_IN: input data of sensor 1
|
||||
* CTRL_OUT: light data + sensor 2
|
||||
* CTRL_IN: input data of sensor 2
|
||||
* CTRL_OUT: light data + sensor 3
|
||||
* CTRL_IN: input data of sensor 3
|
||||
*
|
||||
* Reduce call overhead to pumptools's piuio API for recv and send polling any potential implementation
|
||||
*/
|
||||
if (request_type == PIUIO_DRV_USB_CTRL_TYPE_IN && request == PIUIO_DRV_USB_CTRL_REQUEST) {
|
||||
if (buffer->nbytes != PIUIO_DRV_BUFFER_SIZE) {
|
||||
log_error("Invalid buffer size for ctrl in: %d", buffer->nbytes);
|
||||
return CNH_RESULT_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return _patch_piuio_process_inputs(buffer);
|
||||
#ifdef PATCH_PIUIO_CALL_TRACE
|
||||
log_debug("Read");
|
||||
#endif
|
||||
|
||||
// Only read buffered inputs, no need to trigger another update since
|
||||
// this is taken of by the cycle start
|
||||
|
||||
_patch_piuio_read_inputs_to_buffer(buffer);
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
} else if (request_type == PIUIO_DRV_USB_CTRL_TYPE_OUT && request == PIUIO_DRV_USB_CTRL_REQUEST) {
|
||||
if (buffer->nbytes != PIUIO_DRV_BUFFER_SIZE) {
|
||||
log_error("Invalid buffer size for ctrl out: %d", buffer->nbytes);
|
||||
return CNH_RESULT_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return _patch_piuio_process_outputs(buffer);
|
||||
_patch_piuio_read_outputs_from_buffer(buffer);
|
||||
|
||||
// Sync properly with sensor cycling by application
|
||||
// Note: Naturally, the update code below will break if sensors are not cycled
|
||||
// as expected
|
||||
_patch_piuio_sensor_group = _patch_piuio_get_sensor_group_from_buffer(buffer);
|
||||
|
||||
#ifdef PATCH_PIUIO_CALL_TRACE
|
||||
log_debug("Write: %d", _patch_piuio_sensor_group);
|
||||
#endif
|
||||
|
||||
// Trigger exactly ONE full update cycle on the API implementation on
|
||||
// every first call of the whole update cycle
|
||||
|
||||
if (_patch_piuio_sensor_group == 0) {
|
||||
#ifdef PATCH_PIUIO_CALL_TRACE
|
||||
log_debug("Update API");
|
||||
#endif
|
||||
|
||||
if (!_patch_piuio_api.send()) {
|
||||
log_error("Sending outputs on api piuio %s failed", _patch_piuio_api.ident());
|
||||
return CNH_RESULT_OTHER_ERROR;
|
||||
}
|
||||
|
||||
if (!_patch_piuio_api.recv()) {
|
||||
log_error("Receiving inputs on api piuio %s failed", _patch_piuio_api.ident());
|
||||
return CNH_RESULT_OTHER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
} else if (request_type == 0 && request == 0) {
|
||||
// ITG 2/PIU Pro kernel hack, can be handled by piuio-khack module
|
||||
// Safety net for visibility if the module is missing
|
||||
@ -134,17 +192,12 @@ static void _patch_piuio_close(void)
|
||||
_patch_piuio_api.close();
|
||||
}
|
||||
|
||||
static enum cnh_result _patch_piuio_process_inputs(struct cnh_iobuf* buffer)
|
||||
static void _patch_piuio_read_inputs_to_buffer(struct cnh_iobuf* buffer)
|
||||
{
|
||||
struct ptapi_io_piuio_pad_inputs p1_pad_in;
|
||||
struct ptapi_io_piuio_pad_inputs p2_pad_in;
|
||||
struct ptapi_io_piuio_sys_inputs sys_in;
|
||||
|
||||
if (!_patch_piuio_api.recv()) {
|
||||
log_error("Receiving inputs on api piuio %s failed", _patch_piuio_api.ident());
|
||||
return CNH_RESULT_OTHER_ERROR;
|
||||
}
|
||||
|
||||
memset(&p1_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs));
|
||||
memset(&p2_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs));
|
||||
memset(&sys_in, 0, sizeof(struct ptapi_io_piuio_sys_inputs));
|
||||
@ -201,71 +254,32 @@ static enum cnh_result _patch_piuio_process_inputs(struct cnh_iobuf* buffer)
|
||||
/* Player 1 */
|
||||
buffer->bytes[0] = 0;
|
||||
|
||||
if (p1_pad_in.lu) {
|
||||
buffer->bytes[0] |= (1 << 0);
|
||||
}
|
||||
|
||||
if (p1_pad_in.ru) {
|
||||
buffer->bytes[0] |= (1 << 1);
|
||||
}
|
||||
|
||||
if (p1_pad_in.cn) {
|
||||
buffer->bytes[0] |= (1 << 2);
|
||||
}
|
||||
|
||||
if (p1_pad_in.ld) {
|
||||
buffer->bytes[0] |= (1 << 3);
|
||||
}
|
||||
|
||||
if (p1_pad_in.rd) {
|
||||
buffer->bytes[0] |= (1 << 4);
|
||||
}
|
||||
buffer->bytes[0] |= ((p1_pad_in.lu ? 1 : 0) << 0);
|
||||
buffer->bytes[0] |= ((p1_pad_in.ru ? 1 : 0) << 1);
|
||||
buffer->bytes[0] |= ((p1_pad_in.cn ? 1 : 0) << 2);
|
||||
buffer->bytes[0] |= ((p1_pad_in.ld ? 1 : 0) << 3);
|
||||
buffer->bytes[0] |= ((p1_pad_in.rd ? 1 : 0) << 4);
|
||||
|
||||
buffer->bytes[0] ^= 0xFF;
|
||||
|
||||
/* Player 2 */
|
||||
buffer->bytes[2] = 0;
|
||||
|
||||
/* Player 2 */
|
||||
if (p2_pad_in.lu) {
|
||||
buffer->bytes[2] |= (1 << 0);
|
||||
}
|
||||
|
||||
if (p2_pad_in.ru) {
|
||||
buffer->bytes[2] |= (1 << 1);
|
||||
}
|
||||
|
||||
if (p2_pad_in.cn) {
|
||||
buffer->bytes[2] |= (1 << 2);
|
||||
}
|
||||
|
||||
if (p2_pad_in.ld) {
|
||||
buffer->bytes[2] |= (1 << 3);
|
||||
}
|
||||
|
||||
if (p2_pad_in.rd) {
|
||||
buffer->bytes[2] |= (1 << 4);
|
||||
}
|
||||
buffer->bytes[2] |= ((p1_pad_in.lu ? 1 : 0) << 0);
|
||||
buffer->bytes[2] |= ((p1_pad_in.ru ? 1 : 0) << 1);
|
||||
buffer->bytes[2] |= ((p1_pad_in.cn ? 1 : 0) << 2);
|
||||
buffer->bytes[2] |= ((p1_pad_in.ld ? 1 : 0) << 3);
|
||||
buffer->bytes[2] |= ((p1_pad_in.rd ? 1 : 0) << 4);
|
||||
|
||||
buffer->bytes[2] ^= 0xFF;
|
||||
|
||||
/* Sys */
|
||||
buffer->bytes[1] = 0;
|
||||
|
||||
/* Sys */
|
||||
if (sys_in.test) {
|
||||
buffer->bytes[1] |= (1 << 1);
|
||||
}
|
||||
|
||||
if (sys_in.service) {
|
||||
buffer->bytes[1] |= (1 << 6);
|
||||
}
|
||||
|
||||
if (sys_in.clear) {
|
||||
buffer->bytes[1] |= (1 << 7);
|
||||
}
|
||||
|
||||
if (sys_in.coin) {
|
||||
buffer->bytes[1] |= (1 << 2);
|
||||
}
|
||||
buffer->bytes[1] |= ((sys_in.test ? 1 : 0) << 1);
|
||||
buffer->bytes[1] |= ((sys_in.service ? 1 : 0) << 6);
|
||||
buffer->bytes[1] |= ((sys_in.clear ? 1 : 0) << 7);
|
||||
buffer->bytes[1] |= ((sys_in.coin ? 1 : 0) << 2);
|
||||
|
||||
buffer->bytes[1] ^= 0xFF;
|
||||
|
||||
@ -278,20 +292,14 @@ static enum cnh_result _patch_piuio_process_inputs(struct cnh_iobuf* buffer)
|
||||
}
|
||||
|
||||
buffer->pos = PIUIO_DRV_BUFFER_SIZE;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static enum cnh_result _patch_piuio_process_outputs(struct cnh_iobuf* buffer)
|
||||
static void _patch_piuio_read_outputs_from_buffer(struct cnh_iobuf* buffer)
|
||||
{
|
||||
struct ptapi_io_piuio_pad_outputs p1_pad_out;
|
||||
struct ptapi_io_piuio_pad_outputs p2_pad_out;
|
||||
struct ptapi_io_piuio_cab_outputs cab_out;
|
||||
|
||||
memset(&p1_pad_out, 0, sizeof(struct ptapi_io_piuio_pad_outputs));
|
||||
memset(&p2_pad_out, 0, sizeof(struct ptapi_io_piuio_pad_outputs));
|
||||
memset(&cab_out, 0, sizeof(struct ptapi_io_piuio_cab_outputs));
|
||||
|
||||
/*
|
||||
byte 0:
|
||||
bit 0: sensor id bit 0 select sensor to be read for next input request:
|
||||
@ -336,84 +344,30 @@ static enum cnh_result _patch_piuio_process_outputs(struct cnh_iobuf* buffer)
|
||||
bytes 4 - 7 dummy
|
||||
*/
|
||||
|
||||
_patch_piuio_sensor_group = (enum ptapi_io_piuio_sensor_group) (buffer->bytes[0] & 0x03);
|
||||
p1_pad_out.lu = (buffer->bytes[0] & (1 << 2)) > 0;
|
||||
p1_pad_out.ru = (buffer->bytes[0] & (1 << 3)) > 0;
|
||||
p1_pad_out.cn = (buffer->bytes[0] & (1 << 4)) > 0;
|
||||
p1_pad_out.ld = (buffer->bytes[0] & (1 << 5)) > 0;
|
||||
p1_pad_out.rd = (buffer->bytes[0] & (1 << 6)) > 0;
|
||||
|
||||
/* Player 1 */
|
||||
p2_pad_out.lu = (buffer->bytes[2] & (1 << 2)) > 0;
|
||||
p2_pad_out.ru = (buffer->bytes[2] & (1 << 3)) > 0;
|
||||
p2_pad_out.cn = (buffer->bytes[2] & (1 << 4)) > 0;
|
||||
p2_pad_out.ld = (buffer->bytes[2] & (1 << 5)) > 0;
|
||||
p2_pad_out.rd = (buffer->bytes[2] & (1 << 6)) > 0;
|
||||
|
||||
if (buffer->bytes[0] & (1 << 2)) {
|
||||
p1_pad_out.lu = true;
|
||||
}
|
||||
|
||||
if (buffer->bytes[0] & (1 << 3)) {
|
||||
p1_pad_out.ru = true;
|
||||
}
|
||||
|
||||
if (buffer->bytes[0] & (1 << 4)) {
|
||||
p1_pad_out.cn = true;
|
||||
}
|
||||
|
||||
if (buffer->bytes[0] & (1 << 5)) {
|
||||
p1_pad_out.ld = true;
|
||||
}
|
||||
|
||||
if (buffer->bytes[0] & (1 << 6)) {
|
||||
p1_pad_out.rd = true;
|
||||
}
|
||||
|
||||
/* Player 2 */
|
||||
|
||||
if (buffer->bytes[2] & (1 << 2)) {
|
||||
p2_pad_out.lu = true;
|
||||
}
|
||||
|
||||
if (buffer->bytes[2] & (1 << 3)) {
|
||||
p2_pad_out.ru = true;
|
||||
}
|
||||
|
||||
if (buffer->bytes[2] & (1 << 4)) {
|
||||
p2_pad_out.cn = true;
|
||||
}
|
||||
|
||||
if (buffer->bytes[2] & (1 << 5)) {
|
||||
p2_pad_out.ld = true;
|
||||
}
|
||||
|
||||
if (buffer->bytes[2] & (1 << 6)) {
|
||||
p2_pad_out.rd = true;
|
||||
}
|
||||
|
||||
/* Cabinet */
|
||||
|
||||
if (buffer->bytes[1] & (1 << 2)) {
|
||||
cab_out.bass = true;
|
||||
}
|
||||
|
||||
if (buffer->bytes[2] & (1 << 7)) {
|
||||
cab_out.halo_r2 = true;
|
||||
}
|
||||
|
||||
if (buffer->bytes[3] & (1 << 0)) {
|
||||
cab_out.halo_r1 = true;
|
||||
}
|
||||
|
||||
if (buffer->bytes[3] & (1 << 1)) {
|
||||
cab_out.halo_l2 = true;
|
||||
}
|
||||
|
||||
if (buffer->bytes[3] & (1 << 2)) {
|
||||
cab_out.halo_l1 = true;
|
||||
}
|
||||
cab_out.bass = (buffer->bytes[1] & (1 << 2)) > 0;
|
||||
cab_out.halo_r2 = (buffer->bytes[2] & (1 << 7)) > 0;
|
||||
cab_out.halo_r1 = (buffer->bytes[3] & (1 << 0)) > 0;
|
||||
cab_out.halo_l2 = (buffer->bytes[3] & (1 << 1)) > 0;
|
||||
cab_out.halo_l1 = (buffer->bytes[3] & (1 << 2)) > 0;
|
||||
|
||||
_patch_piuio_api.set_output_pad(0, &p1_pad_out);
|
||||
_patch_piuio_api.set_output_pad(1, &p2_pad_out);
|
||||
_patch_piuio_api.set_output_cab(&cab_out);
|
||||
|
||||
if (!_patch_piuio_api.send()) {
|
||||
log_error("Sending outputs on api piuio %s failed", _patch_piuio_api.ident());
|
||||
return CNH_RESULT_OTHER_ERROR;
|
||||
}
|
||||
|
||||
buffer->pos = PIUIO_DRV_BUFFER_SIZE;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static enum ptapi_io_piuio_sensor_group _patch_piuio_get_sensor_group_from_buffer(struct cnh_iobuf* buffer)
|
||||
{
|
||||
return (enum ptapi_io_piuio_sensor_group) (buffer->bytes[0] & 0x03);
|
||||
}
|
Loading…
Reference in New Issue
Block a user