From 5ab9bcf4953ef4b1c48f330e1340527e683baa62 Mon Sep 17 00:00:00 2001 From: Kai Krakow Date: Mon, 4 Mar 2024 01:13:54 +0100 Subject: [PATCH] xpadneo, core: Handle sync events in xpadneo To properly sync our multiple sub-devices, we need to synchronize the input frame in xpadneo instead of the generic HID handler, otherwise we may see input late or duplicated. See-also: https://github.com/atar-axis/xpadneo/issues/460 See-also: https://github.com/atar-axis/xpadneo/pull/282 Signed-off-by: Kai Krakow --- hid-xpadneo/src/hid-xpadneo.c | 10 +++++++++- hid-xpadneo/src/xpadneo.h | 2 ++ hid-xpadneo/src/xpadneo/core.c | 20 ++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/hid-xpadneo/src/hid-xpadneo.c b/hid-xpadneo/src/hid-xpadneo.c index 39cc2ec2..bede173a 100644 --- a/hid-xpadneo/src/hid-xpadneo.c +++ b/hid-xpadneo/src/hid-xpadneo.c @@ -917,6 +917,7 @@ static int xpadneo_event(struct hid_device *hdev, struct hid_field *field, input_report_key(gamepad, BTN_PADDLES(1), value & 2 ? 1 : 0); input_report_key(gamepad, BTN_PADDLES(2), value & 4 ? 1 : 0); input_report_key(gamepad, BTN_PADDLES(3), value & 8 ? 1 : 0); + xdata->gamepad_sync = true; } goto stop_processing; } else if (usage->type == EV_ABS) { @@ -928,6 +929,7 @@ static int xpadneo_event(struct hid_device *hdev, struct hid_field *field, /* Linux Gamepad Specification */ if (param_gamepad_compliance) { input_report_abs(gamepad, usage->code, value - 32768); + xdata->gamepad_sync = true; goto stop_processing; } break; @@ -967,6 +969,7 @@ static int xpadneo_event(struct hid_device *hdev, struct hid_field *field, if (!keyboard) goto keyboard_missing; input_report_key(keyboard, BTN_SHARE, value); + xdata->keyboard_sync = true; goto stop_processing; } else if (xdata->xbox_button_down && (usage->type == EV_KEY)) { if (!(xdata->quirks & XPADNEO_QUIRK_USE_HW_PROFILES)) { @@ -996,13 +999,16 @@ static int xpadneo_event(struct hid_device *hdev, struct hid_field *field, } /* Let hid-core handle the event */ + xdata->gamepad_sync = true; return 0; combine_z_axes: if (++xdata->count_abs_z_rz == 2) { xdata->count_abs_z_rz = 0; - if (param_enable_rolling_axis) + if (param_enable_rolling_axis) { input_report_abs(gamepad, ABS_MISC, xdata->last_abs_rz - xdata->last_abs_z); + xdata->gamepad_sync = true; + } } return 0; @@ -1114,6 +1120,7 @@ static int xpadneo_probe(struct hid_device *hdev, const struct hid_device_id *id xdata->hdev = hdev; hdev->quirks |= HID_QUIRK_INPUT_PER_APP; + hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; hid_set_drvdata(hdev, xdata); if (hdev->version == 0x00000903) @@ -1281,6 +1288,7 @@ static struct hid_driver xpadneo_driver = { .input_configured = xpadneo_input_configured, .probe = xpadneo_probe, .remove = xpadneo_remove, + .report = xpadneo_report, .report_fixup = xpadneo_report_fixup, .raw_event = xpadneo_raw_event, .event = xpadneo_event, diff --git a/hid-xpadneo/src/xpadneo.h b/hid-xpadneo/src/xpadneo.h index 2a552ff3..727cbc5e 100644 --- a/hid-xpadneo/src/xpadneo.h +++ b/hid-xpadneo/src/xpadneo.h @@ -139,6 +139,7 @@ struct xpadneo_devdata { /* logical device interfaces */ struct hid_device *hdev; struct input_dev *consumer, *gamepad, *keyboard; + bool consumer_sync, gamepad_sync, keyboard_sync; short int missing_reported; /* revert fixups on removal */ @@ -193,5 +194,6 @@ struct xpadneo_devdata { extern int xpadneo_init_consumer(struct xpadneo_devdata *); extern int xpadneo_init_keyboard(struct xpadneo_devdata *); extern int xpadneo_init_synthetic(struct xpadneo_devdata *, char *, struct input_dev **); +extern void xpadneo_report(struct hid_device *, struct hid_report *); #endif diff --git a/hid-xpadneo/src/xpadneo/core.c b/hid-xpadneo/src/xpadneo/core.c index 580d72b6..a338edc5 100644 --- a/hid-xpadneo/src/xpadneo/core.c +++ b/hid-xpadneo/src/xpadneo/core.c @@ -35,3 +35,23 @@ extern int xpadneo_init_synthetic(struct xpadneo_devdata *xdata, char *suffix, *devp = input_dev; return 0; } + +extern void xpadneo_report(struct hid_device *hdev, struct hid_report *report) +{ + struct xpadneo_devdata *xdata = hid_get_drvdata(hdev); + + if (xdata->consumer && xdata->consumer_sync) { + xdata->consumer_sync = false; + input_sync(xdata->consumer); + } + + if (xdata->gamepad && xdata->gamepad_sync) { + xdata->gamepad_sync = false; + input_sync(xdata->gamepad); + } + + if (xdata->keyboard && xdata->keyboard_sync) { + xdata->keyboard_sync = false; + input_sync(xdata->keyboard); + } +}