From 8270e78f47e936d9f7eec4142d814621834866eb Mon Sep 17 00:00:00 2001 From: Sorgelig Date: Thu, 9 Apr 2026 02:32:05 +0800 Subject: [PATCH] xone: backport the paddles from fork. --- drivers/hid/xone/bus/bus.h | 1 + drivers/hid/xone/bus/protocol.c | 34 +++++- drivers/hid/xone/bus/protocol.h | 1 + drivers/hid/xone/driver/gamepad.c | 184 +++++++++++++++++++++++++++++- 4 files changed, 217 insertions(+), 3 deletions(-) diff --git a/drivers/hid/xone/bus/bus.h b/drivers/hid/xone/bus/bus.h index c107e1e3f..37cd87d01 100644 --- a/drivers/hid/xone/bus/bus.h +++ b/drivers/hid/xone/bus/bus.h @@ -97,6 +97,7 @@ struct gip_driver_ops { int (*audio_volume)(struct gip_client *client, u8 in, u8 out); int (*hid_report)(struct gip_client *client, void *data, u32 len); int (*input)(struct gip_client *client, void *data, u32 len); + int (*firmware)(struct gip_client *client, void *data, u32 len); int (*audio_samples)(struct gip_client *client, void *data, u32 len); }; diff --git a/drivers/hid/xone/bus/protocol.c b/drivers/hid/xone/bus/protocol.c index 1f24a0d22..4b8a12686 100644 --- a/drivers/hid/xone/bus/protocol.c +++ b/drivers/hid/xone/bus/protocol.c @@ -379,7 +379,7 @@ static int gip_send_pkt(struct gip_client *client, if (err) return err; - memcpy(client->chunk_buf_in->data, data, hdr->chunk_offset); + if(data) memcpy(client->chunk_buf_in->data, data, hdr->chunk_offset); return 0; } @@ -691,6 +691,20 @@ int gip_init_audio_out(struct gip_client *client) } EXPORT_SYMBOL_GPL(gip_init_audio_out); +int gip_init_extra_data(struct gip_client *client) +{ + struct gip_header hdr = { + .command = 0x4d, // ??? + .options = GIP_OPT_ACKNOWLEDGE, // Because 4 + .sequence = 1, + .packet_length = 2, + }; + u8 packet_data[] = { 0x07, 0x00 }; + + return gip_send_pkt(client, &hdr, &packet_data); +} +EXPORT_SYMBOL_GPL(gip_init_extra_data); + void gip_disable_audio(struct gip_client *client) { struct gip_adapter *adap = client->adapter; @@ -1402,6 +1416,22 @@ static int gip_handle_pkt_audio_samples(struct gip_client *client, return err; } +static int gip_handle_pkt_firmware(struct gip_client *client, void *data, + u32 len) +{ + int err = 0; + + if (down_trylock(&client->drv_lock)) + return -EBUSY; + + if (client->drv && client->drv->ops.firmware) + err = client->drv->ops.firmware(client, data, len); + + up(&client->drv_lock); + + return err; +} + static int gip_dispatch_pkt(struct gip_client *client, struct gip_header *hdr, void *data, u32 len) { @@ -1433,6 +1463,8 @@ static int gip_dispatch_pkt(struct gip_client *client, switch (hdr->command) { case GIP_CMD_INPUT: return gip_handle_pkt_input(client, data, len); + case GIP_CMD_FIRMWARE: + return gip_handle_pkt_firmware(client, data, len); } return 0; diff --git a/drivers/hid/xone/bus/protocol.h b/drivers/hid/xone/bus/protocol.h index 96722c863..2f90018f5 100644 --- a/drivers/hid/xone/bus/protocol.h +++ b/drivers/hid/xone/bus/protocol.h @@ -110,6 +110,7 @@ int gip_send_rumble(struct gip_client *client, void *pkt, u32 len); int gip_set_led_mode(struct gip_client *client, enum gip_led_mode mode, u8 brightness); int gip_send_audio_samples(struct gip_client *client, void *samples); +int gip_init_extra_data(struct gip_client *client); bool gip_has_interface(struct gip_client *client, const guid_t *guid); int gip_set_encryption_key(struct gip_client *client, u8 *key, int len); diff --git a/drivers/hid/xone/driver/gamepad.c b/drivers/hid/xone/driver/gamepad.c index 891dbdb9a..1d07ae8b2 100644 --- a/drivers/hid/xone/driver/gamepad.c +++ b/drivers/hid/xone/driver/gamepad.c @@ -13,12 +13,32 @@ #define GIP_GP_NAME "Microsoft Xbox Controller" +#define GIP_VENDOR_MICROSOFT 0x045e +#define GIP_PRODUCT_ELITE_SERIES_2 0x0b00 +#define GIP_PRODUCT_ELITE 0x02e3 + +/* + * Various versions of the Elite Series 2 firmware have changed the way paddle + * states are sent. Paddle support is only reported up to this firmware + * version. + */ +#define GIP_ELITE_SERIES_2_4X_FIRMWARE 0x04FF +#define GIP_ELITE_SERIES_2_510_FIRMWARE 0x050A + #define GIP_GP_RUMBLE_DELAY msecs_to_jiffies(10) #define GIP_GP_RUMBLE_MAX 100 /* button offset from end of packet */ #define GIP_GP_BTN_SHARE_OFFSET 18 +/* fallback for kernels < 6.17 */ +#ifndef BTN_GRIPR +#define BTN_GRIPR BTN_TRIGGER_HAPPY5 +#define BTN_GRIPR2 BTN_TRIGGER_HAPPY6 +#define BTN_GRIPL BTN_TRIGGER_HAPPY7 +#define BTN_GRIPL2 BTN_TRIGGER_HAPPY8 +#endif + static const guid_t gip_gamepad_guid_share = GUID_INIT(0xecddd2fe, 0xd387, 0x4294, 0xbd, 0x96, 0x1a, 0x71, 0x2e, 0x3d, 0xc7, 0x7d); @@ -44,6 +64,13 @@ enum gip_gamepad_button { GIP_GP_BTN_STICK_R = BIT(15), }; +enum gip_gamepad_paddle { + GIP_GP_BTN_P1 = BIT(0), + GIP_GP_BTN_P2 = BIT(1), + GIP_GP_BTN_P3 = BIT(2), + GIP_GP_BTN_P4 = BIT(3), +}; + enum gip_gamepad_motor { GIP_GP_MOTOR_R = BIT(0), GIP_GP_MOTOR_L = BIT(1), @@ -51,6 +78,17 @@ enum gip_gamepad_motor { GIP_GP_MOTOR_LT = BIT(3), }; +/* + * Remember, xpad keeps the 4 bytes. + * Paddles are at [18] in xpad, so, [14] here. + * Pad 14 bytes. + */ +struct gip_gamepad_pkt_firmware { + u8 unknown[14]; + u8 paddles; + u8 profile; +} __packed; + struct gip_gamepad_pkt_input { __le16 buttons; __le16 trigger_left; @@ -78,6 +116,14 @@ struct gip_gamepad_pkt_rumble { u8 repeat; } __packed; +typedef enum PaddleCapability { + PADDLE_NONE, + PADDLE_ELITE, + PADDLE_ELITE2_4X, // Still in the same packet + PADDLE_ELITE2_510, // Same packet, different location + PADDLE_ELITE2_511, // Different packet entirely. +} PaddleCapability; + struct gip_gamepad { struct gip_client *client; struct gip_battery battery; @@ -87,6 +133,7 @@ struct gip_gamepad { bool supports_share; bool supports_dli; + PaddleCapability paddle_support; struct gip_gamepad_rumble { /* serializes access to rumble packet */ @@ -163,6 +210,45 @@ static int gip_gamepad_init_rumble(struct gip_gamepad *gamepad) return input_ff_create_memless(dev, NULL, gip_gamepad_queue_rumble); } +static int gip_gamepad_init_extra_data(struct gip_gamepad *gamepad) +{ + return gip_init_extra_data(gamepad->client); +} + +static void gip_gamepad_query_paddles(struct gip_gamepad *gamepad) +{ + struct gip_hardware hardware = gamepad->client->hardware; + + gamepad->paddle_support = PADDLE_NONE; + + if (hardware.vendor != GIP_VENDOR_MICROSOFT) + return; + + if (hardware.product == GIP_PRODUCT_ELITE) { + pr_debug("%s: Elite Series 1\n", __func__); + gamepad->paddle_support = PADDLE_ELITE; + return; + } + + if (hardware.product != GIP_PRODUCT_ELITE_SERIES_2) { + pr_debug("%s: MS controller, no paddle support", __func__); + return; + } + + pr_debug("%s: Elite Series 2\n", __func__); + if (hardware.version <= GIP_ELITE_SERIES_2_4X_FIRMWARE) + gamepad->paddle_support = PADDLE_ELITE2_4X; + + else if (hardware.version <= GIP_ELITE_SERIES_2_510_FIRMWARE) + gamepad->paddle_support = PADDLE_ELITE2_510; + + // If new revisions come, this should become LTE new max + else if (hardware.version > GIP_ELITE_SERIES_2_510_FIRMWARE) { + pr_debug("%s: FW > 5.10\n", __func__); + gamepad->paddle_support = PADDLE_ELITE2_511; + } +} + static int gip_gamepad_init_input(struct gip_gamepad *gamepad) { struct input_dev *dev = gamepad->input.dev; @@ -176,6 +262,14 @@ static int gip_gamepad_init_input(struct gip_gamepad *gamepad) if (gamepad->supports_share) input_set_capability(dev, EV_KEY, KEY_RECORD); + if (gamepad->paddle_support) { + pr_debug("%s: Paddle support detected", __func__); + input_set_capability(dev, EV_KEY, BTN_GRIPR); + input_set_capability(dev, EV_KEY, BTN_GRIPR2); + input_set_capability(dev, EV_KEY, BTN_GRIPL); + input_set_capability(dev, EV_KEY, BTN_GRIPL2); + } + input_set_capability(dev, EV_KEY, BTN_MODE); input_set_capability(dev, EV_KEY, BTN_START); input_set_capability(dev, EV_KEY, BTN_SELECT); @@ -218,7 +312,6 @@ err_delete_timer: #else timer_delete_sync(&gamepad->rumble.timer); #endif - return err; } @@ -251,6 +344,30 @@ static int gip_gamepad_op_guide_button(struct gip_client *client, bool down) return 0; } +static int gip_gamepad_op_firmware(struct gip_client *client, void *data, + u32 len) +{ + struct gip_gamepad *gamepad; + struct input_dev *dev; + + // First, ensure the data is of the correct size. + struct gip_gamepad_pkt_firmware *pkt = data; + if (len < sizeof(*pkt)) + return -EINVAL; + + // Grab our controller + gamepad = dev_get_drvdata(&client->dev); + dev = gamepad->input.dev; + + input_report_key(dev, BTN_GRIPR, pkt->paddles & GIP_GP_BTN_P1); + input_report_key(dev, BTN_GRIPR2, pkt->paddles & GIP_GP_BTN_P2); + input_report_key(dev, BTN_GRIPL, pkt->paddles & GIP_GP_BTN_P3); + input_report_key(dev, BTN_GRIPL2, pkt->paddles & GIP_GP_BTN_P4); + + input_sync(dev); + return 0; +} + static int gip_gamepad_op_input(struct gip_client *client, void *data, u32 len) { struct gip_gamepad *gamepad = dev_get_drvdata(&client->dev); @@ -258,6 +375,8 @@ static int gip_gamepad_op_input(struct gip_client *client, void *data, u32 len) struct input_dev *dev = gamepad->input.dev; u16 buttons; u8 share_offset = GIP_GP_BTN_SHARE_OFFSET; + int report_paddles = 0, series_1 = 0; + u8 paddles; if (len < sizeof(*pkt)) return -EINVAL; @@ -286,6 +405,54 @@ static int gip_gamepad_op_input(struct gip_client *client, void *data, u32 len) input_report_key(dev, BTN_TR, buttons & GIP_GP_BTN_BUMPER_R); input_report_key(dev, BTN_THUMBL, buttons & GIP_GP_BTN_STICK_L); input_report_key(dev, BTN_THUMBR, buttons & GIP_GP_BTN_STICK_R); + + /* + * For anyone comparing to xpad's paddle handling source, xone strips + * four bytes of header off of the beginning that xpad doesn't, so all + * offsets are 4 less later revisions put paddle support in the firmware + * packet, check gip_gamepad_op_WTFEVER + * + * For 5.10 and below, the paddle data is in various locations within + * the main input packet, for 5.11 and above the data is stored in a + * separate packet and handeled by gip_gamepad_op_firmware(). + */ + + // Assume the controller might not send profile data, check length + if (gamepad->paddle_support == PADDLE_ELITE2_510 && len > 18) { + /* + * On the Elite Series 2 with newer-ISH firmware (<=5.10) + * paddles are stored at byte 18 (22) + */ + paddles = ((u8 *)data)[18]; + report_paddles = 1; + + } else if (gamepad->paddle_support == PADDLE_ELITE2_4X && len > 14) { + /* + * On the Elite Series 2 with older firmware (<5.0) + * paddles are stored at byte 14 (18) + */ + paddles = ((u8 *)data)[14]; + report_paddles = 1; + + } else if (gamepad->paddle_support == PADDLE_ELITE && len > 28) { + // On the original Elite, paddles are stored at byte 28 + paddles = ((u8 *)data)[28]; + report_paddles = 1; + series_1 = 1; + } + + // Series 1 reports paddles as different buttons than newer ones + if (report_paddles) { + input_report_key(dev, BTN_GRIPR, paddles & + (series_1 ? GIP_GP_BTN_P2 : GIP_GP_BTN_P1)); + input_report_key(dev, BTN_GRIPR2, paddles & + (series_1 ? GIP_GP_BTN_P4 : GIP_GP_BTN_P2)); + input_report_key(dev, BTN_GRIPL, paddles & + (series_1 ? GIP_GP_BTN_P1 : GIP_GP_BTN_P3)); + input_report_key(dev, BTN_GRIPL2, paddles & + (series_1 ? GIP_GP_BTN_P3 : GIP_GP_BTN_P4)); + } + input_report_abs(dev, ABS_X, (s16)le16_to_cpu(pkt->stick_left_x)); input_report_abs(dev, ABS_RX, (s16)le16_to_cpu(pkt->stick_right_x)); input_report_abs(dev, ABS_Y, ~(s16)le16_to_cpu(pkt->stick_left_y)); @@ -297,7 +464,6 @@ static int gip_gamepad_op_input(struct gip_client *client, void *data, u32 len) input_report_abs(dev, ABS_HAT0Y, !!(buttons & GIP_GP_BTN_DPAD_D) - !!(buttons & GIP_GP_BTN_DPAD_U)); input_sync(dev); - return 0; } @@ -316,6 +482,19 @@ static int gip_gamepad_probe(struct gip_client *client) if (err) return err; + gip_gamepad_query_paddles(gamepad); + + /* + * xpad sends this for all Elite 2 firmware versions, + * but it seems to be only necessary for 5.11 paddles. + */ + if(gamepad->paddle_support == PADDLE_ELITE2_511) + { + err = gip_gamepad_init_extra_data(gamepad); + if (err) + return err; + } + err = gip_init_battery(&gamepad->battery, client, GIP_GP_NAME); if (err) return err; @@ -360,6 +539,7 @@ static struct gip_driver gip_gamepad_driver = { .authenticate = gip_gamepad_op_authenticate, .guide_button = gip_gamepad_op_guide_button, .input = gip_gamepad_op_input, + .firmware = gip_gamepad_op_firmware, }, .probe = gip_gamepad_probe, .remove = gip_gamepad_remove,