From 20d3eb89348ffa20e80e649eeaba672d3b2e3538 Mon Sep 17 00:00:00 2001 From: Charles Munger Date: Sat, 27 Apr 2024 14:33:11 -0700 Subject: [PATCH] Add paddles support for the Elite Series 2 firmware versions < 5.x Tested with firmware 4.7 and evtest. Works in Steam Input when no profile is selected on the controller. Input event codes are the same as what xpad reports for paddles, so most controller profiles should work in both wired and wireless modes. --- driver/gamepad.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/driver/gamepad.c b/driver/gamepad.c index eec2aea..a3ea25f 100644 --- a/driver/gamepad.c +++ b/driver/gamepad.c @@ -12,6 +12,13 @@ #define GIP_GP_NAME "Microsoft Xbox Controller" +#define GIP_VENDOR_MICROSOFT 0x045e +#define GIP_PRODUCT_ELITE_SERIES_2 0x0b00 +// 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_MAX_FIRMWARE 0x04FF + #define GIP_GP_RUMBLE_DELAY msecs_to_jiffies(10) #define GIP_GP_RUMBLE_MAX 100 @@ -43,6 +50,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), @@ -86,6 +100,7 @@ struct gip_gamepad { bool supports_share; bool supports_dli; + bool supports_paddles; struct gip_gamepad_rumble { /* serializes access to rumble packet */ @@ -160,6 +175,7 @@ static int gip_gamepad_init_rumble(struct gip_gamepad *gamepad) static int gip_gamepad_init_input(struct gip_gamepad *gamepad) { struct input_dev *dev = gamepad->input.dev; + struct gip_hardware hardware = gamepad->client->hardware; int err; gamepad->supports_share = gip_has_interface(gamepad->client, @@ -167,9 +183,20 @@ static int gip_gamepad_init_input(struct gip_gamepad *gamepad) gamepad->supports_dli = gip_has_interface(gamepad->client, &gip_gamepad_guid_dli); + gamepad->supports_paddles = hardware.vendor == GIP_VENDOR_MICROSOFT + && hardware.product == GIP_PRODUCT_ELITE_SERIES_2 + && hardware.version <= GIP_ELITE_SERIES_2_MAX_FIRMWARE; + if (gamepad->supports_share) input_set_capability(dev, EV_KEY, KEY_RECORD); + if (gamepad->supports_paddles) { + input_set_capability(dev, EV_KEY, BTN_TRIGGER_HAPPY5); + input_set_capability(dev, EV_KEY, BTN_TRIGGER_HAPPY6); + input_set_capability(dev, EV_KEY, BTN_TRIGGER_HAPPY7); + input_set_capability(dev, EV_KEY, BTN_TRIGGER_HAPPY8); + } + input_set_capability(dev, EV_KEY, BTN_MODE); input_set_capability(dev, EV_KEY, BTN_START); input_set_capability(dev, EV_KEY, BTN_SELECT); @@ -276,6 +303,17 @@ 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); + + + if (gamepad->supports_paddles && len > sizeof(struct gip_gamepad_pkt_input)) { + // On the original Elite Series 2 firmware paddles are stored right after other data in the packet + u8 paddles = ((u8 *) data)[sizeof(struct gip_gamepad_pkt_input)]; + input_report_key(dev, BTN_TRIGGER_HAPPY5, paddles & GIP_GP_BTN_P1); + input_report_key(dev, BTN_TRIGGER_HAPPY6, paddles & GIP_GP_BTN_P2); + input_report_key(dev, BTN_TRIGGER_HAPPY7, paddles & GIP_GP_BTN_P3); + input_report_key(dev, BTN_TRIGGER_HAPPY8, paddles & 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));