Compare commits

...

6 Commits
5.46 ... 5.47

Author SHA1 Message Date
icex2
bdf493d2fb chore: Update changelog for 5.47 release 2024-01-29 22:08:28 +01:00
icex2
bec007d52a fix(p3ioemu): Incorrect dispatching of unknown p3io commands
Using ddrhook1, this caused DDR X to crash on startup when the
P3io client sends the currently unknown command 2B. Handling it
with the incorrect p3io command struct, any following reading
attempts from the P3IO by the game fail.

Handle the 2B case explicitly with a generic response that worked
previously before the restructuring of the code. Apply the same
to any further unknown commands with improved logging warning
about this.
2023-11-30 20:33:36 +01:00
icex2
a177913bd6 fix(p3io): Off-by-one error on assert
Buffers are allowed to have the exact size as the max defined
P3IO buffer size. Cutting it short by one byte causes this
to fail incorrectly when using the pure raw buffer structure
2023-11-30 20:33:36 +01:00
ahnada
0fdde8b32d Allow generic HID devices with broken(?) outputs to still work as inputs.
Fixes Sony DualShock 4 not working
2023-11-13 21:35:28 +01:00
ahnada
09b3a6c24a Fix incorrect SetupDiGetClassDevs error checking 2023-11-13 19:37:29 +01:00
icex2
f8b2f5f40d chore: Bump version to 5.47 to start next development cycle 2023-11-03 15:48:04 +01:00
8 changed files with 71 additions and 16 deletions

View File

@@ -2,6 +2,15 @@
Note for CI/CD: Ensure the version formatting in the sections is kept identical to the versions
given in tags. The pipeline will pick this up and cuts out the relevant section for release notes.
## 5.47
### Features
N/A
### Fixes
* fix(ddr/p3ioemu): Handle unknown 2B command to fix DDR X IO errors
* fix(ddr/p3io): Crash on all supported DDR games due to incorrect p3io message size validation
* fix(geninput): Sony DualShock 4 not working
## 5.46
### Features
* feat(ddrio): Wrapper/shim library to drive another ddrio in a dedicated IO thread. Improves performance for highly IO

View File

@@ -1,6 +1,6 @@
# Bemanitools 5
Version: `5.46`
Version: `5.47`
[Changelog](CHANGELOG.md)

View File

@@ -20,7 +20,7 @@ void dev_list_init(struct dev_list *devs, const GUID *class_guid)
devs->infolist = SetupDiGetClassDevs(
devs->class_guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (devs->infolist == NULL) {
if (devs->infolist == INVALID_HANDLE_VALUE) {
log_fatal(
"SetupDiGetClassDevs failed: %08x", (unsigned int) GetLastError());
}

View File

@@ -48,7 +48,12 @@ arrays_fail:
hid_meta_out_fini_caps(meta);
caps_fail:
return false;
/**
* Still allow the device to be used as input.
* Useful for devices like the Sony DUALSHOCK 4, where it indicates it can receive outputs
* but it errors out when trying to initialize an output report.
*/
return true;
}
static bool
@@ -99,9 +104,11 @@ hid_meta_out_init_caps(struct hid_meta_out *meta, PHIDP_PREPARSED_DATA ppd)
caps_val_fail:
free(meta->caps_val);
meta->caps_val = NULL;
caps_btn_fail:
free(meta->caps_btn);
meta->caps_btn = NULL;
caps_tlc_fail:
return false;
@@ -114,7 +121,6 @@ static bool hid_meta_out_init_arrays(struct hid_meta_out *meta)
bool *report_presence;
unsigned int nreports;
unsigned int i;
uint8_t *bytes;
size_t nbytes;
size_t count;
@@ -174,7 +180,6 @@ static bool hid_meta_out_init_arrays(struct hid_meta_out *meta)
for (i = 0; i < 0x100; i++) {
if (report_presence[i]) {
nbytes = meta->caps_tlc.OutputReportByteLength;
bytes = xmalloc(meta->caps_tlc.OutputReportByteLength);
if (!hid_report_out_init(
&meta->reports[meta->nreports],
@@ -198,14 +203,22 @@ static bool hid_meta_out_init_arrays(struct hid_meta_out *meta)
return true;
r_init_fail:
free(bytes);
for (i = meta->nreports; i > 0; i--) {
hid_report_out_fini(&meta->reports[i - 1]);
}
free(report_presence);
// Clear out all output/light data
meta->nreports = 0;
free(meta->reports);
meta->reports = NULL;
meta->nlights = 0;
meta->nbuttons = 0;
// Failed out before allocating memory
meta->lights = NULL;
meta->priv_lights = NULL;
return false;
}
@@ -433,5 +446,8 @@ static void hid_meta_out_fini_arrays(struct hid_meta_out *meta)
static void hid_meta_out_fini_caps(struct hid_meta_out *meta)
{
free(meta->caps_btn);
meta->caps_btn = NULL;
free(meta->caps_val);
meta->caps_val = NULL;
}

View File

@@ -57,7 +57,7 @@ static HANDLE mm_open_device(void)
dev_info = SetupDiGetClassDevsW(
&hid_guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (dev_info == NULL) {
if (dev_info == INVALID_HANDLE_VALUE) {
log_fatal("SetupDiGetClassDevs failed");
}

View File

@@ -41,7 +41,7 @@ void p3io_resp_hdr_init(
{
log_assert(resp_hdr != NULL);
log_assert(req_hdr != NULL);
log_assert(nbytes < P3IO_MAX_MESSAGE_SIZE);
log_assert(nbytes <= P3IO_MAX_MESSAGE_SIZE);
/* Length byte in this packet format counts everything from the length
byte onwards. The length byte itself occurs at the start of the frame. */

View File

@@ -161,6 +161,11 @@ struct p3io_req_rs232_write {
uint8_t bytes[128];
};
struct p3io_req_unknown_generic {
struct p3io_hdr hdr;
uint8_t unknown;
};
struct p3io_req_raw {
uint8_t data[P3IO_MAX_MESSAGE_SIZE];
};
@@ -182,6 +187,7 @@ union p3io_req_any {
struct p3io_req_rs232_open_close rs232_open_close;
struct p3io_req_rs232_read rs232_read;
struct p3io_req_rs232_write rs232_write;
struct p3io_req_unknown_generic unknown_generic;
struct p3io_req_raw raw;
};
@@ -266,6 +272,11 @@ struct p3io_resp_rs232_write {
uint8_t nbytes;
};
struct p3io_resp_unknown_generic {
struct p3io_hdr hdr;
uint8_t unknown;
};
struct p3io_resp_raw {
uint8_t data[P3IO_MAX_MESSAGE_SIZE];
};
@@ -286,6 +297,7 @@ union p3io_resp_any {
struct p3io_resp_rs232_open_close rs232_open_close;
struct p3io_resp_rs232_read rs232_read;
struct p3io_resp_rs232_write rs232_write;
struct p3io_resp_unknown_generic unknown_generic;
struct p3io_resp_raw raw;
};

View File

@@ -49,6 +49,8 @@ static void p3io_cmd_get_video_freq(
const struct p3io_req_get_video_freq *req,
struct p3io_resp_get_video_freq *resp);
static void
p3io_cmd_unknown_2b(const struct p3io_req_unknown_2b *req, struct p3io_resp_unknown_2b *resp);
static void
p3io_cmd_init(const struct p3io_req_init *req, struct p3io_resp_init *resp);
static void p3io_cmd_get_coinstock(
const struct p3io_req_coin_stock *req, struct p3io_resp_coin_stock *resp);
@@ -56,7 +58,7 @@ static void p3io_cmd_set_coin_counter(
const struct p3io_req_set_coin_counter *req,
struct p3io_resp_set_coin_counter *resp);
static void
p3io_cmd_unknown(const union p3io_req_any *req, struct p3io_resp_raw *resp);
p3io_cmd_unknown(const struct p3io_req_unknown_generic *req, struct p3io_resp_unknown_generic *resp);
void p3io_emu_init(const struct p3io_ops *ops, void *ctx)
{
@@ -268,6 +270,11 @@ static HRESULT p3io_cmd_dispatch(const union p3io_req_any *req)
break;
case P3IO_CMD_UNKNOWN_2B:
p3io_cmd_unknown_2b(&req->unknown_2b, &resp.unknown_2b);
break;
case P3IO_CMD_INIT:
p3io_cmd_init(&req->init, &resp.init);
@@ -301,7 +308,7 @@ static HRESULT p3io_cmd_dispatch(const union p3io_req_any *req)
break;
default:
p3io_cmd_unknown(req, &resp.raw);
p3io_cmd_unknown(&req->unknown_generic, &resp.unknown_generic);
break;
}
@@ -511,6 +518,16 @@ static void p3io_cmd_get_video_freq(
}
}
static void
p3io_cmd_unknown_2b(const struct p3io_req_unknown_2b *req, struct p3io_resp_unknown_2b *resp)
{
log_misc("Unknown 2b");
p3io_resp_hdr_init(&resp->hdr, sizeof(*resp), &req->hdr);
resp->unknown = 0;
}
static void
p3io_cmd_init(const struct p3io_req_init *req, struct p3io_resp_init *resp)
{
@@ -557,15 +574,16 @@ static void p3io_cmd_set_coin_counter(
}
static void
p3io_cmd_unknown(const union p3io_req_any *req, struct p3io_resp_raw *resp)
p3io_cmd_unknown(const struct p3io_req_unknown_generic *req, struct p3io_resp_unknown_generic *resp)
{
log_warning("Unsupported P3IO command: %02x", req->hdr.cmd);
log_warning("Unsupported P3IO command, sending default response (might not work/crash though): %02x",
req->hdr.cmd);
p3io_resp_hdr_init(
(struct p3io_hdr *) &resp->data, sizeof(*resp), &req->hdr);
p3io_resp_hdr_init(&resp->hdr, sizeof(*resp), &req->hdr);
// Not always applicable/correct as there are several commands not
// responding with any data, but fine for the majority of (unsupported)
// commands
resp->data[sizeof(struct p3io_hdr) + 0] = 0;
// Remark: This might also lead to unpredictable behaviour or crashes
resp->unknown = 0;
}