SDL: Added support for the Xbox One Elite 2 Controller with 5.x series firmware

From 64882b24663986f39e5e7208abccfa2698e0dabf Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 12 Aug 2021 08:17:08 -0700
Subject: [PATCH] Added support for the Xbox One Elite 2 Controller with 5.x
 series firmware

---
 src/joystick/SDL_joystick.c              |  1 +
 src/joystick/controller_type.h           |  3 +-
 src/joystick/hidapi/SDL_hidapi_xboxone.c | 22 ++++++--
 src/joystick/usb_ids.h                   | 69 ++++++++++++------------
 4 files changed, 56 insertions(+), 39 deletions(-)

diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index 1bab305b0b..7e58357043 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -1989,6 +1989,7 @@ SDL_IsJoystickBluetoothXboxOne(Uint16 vendor_id, Uint16 product_id)
         if (product_id == USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH ||
             product_id == USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH ||
             product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH ||
+            product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_REV2_BLUETOOTH ||
             product_id == USB_PRODUCT_XBOX_SERIES_X_BLUETOOTH) {
             return SDL_TRUE;
         }
diff --git a/src/joystick/controller_type.h b/src/joystick/controller_type.h
index 7476740dd0..0488cfc5a8 100644
--- a/src/joystick/controller_type.h
+++ b/src/joystick/controller_type.h
@@ -328,6 +328,7 @@ static const ControllerDescription_t arrControllers[] = {
 	{ MAKE_CONTROLLER_ID( 0x045e, 0x0b05 ), k_eControllerType_XBoxOneController, "Xbox One Elite 2 Controller" },	// Microsoft X-Box One Elite Series 2 pad (Bluetooth)
 	{ MAKE_CONTROLLER_ID( 0x045e, 0x0b12 ), k_eControllerType_XBoxOneController, "Xbox Series X Controller" },	// Microsoft X-Box Series X pad
 	{ MAKE_CONTROLLER_ID( 0x045e, 0x0b13 ), k_eControllerType_XBoxOneController, "Xbox Series X Controller" },	// Microsoft X-Box Series X pad (Bluetooth)
+	{ MAKE_CONTROLLER_ID( 0x045e, 0x0b22 ), k_eControllerType_XBoxOneController, "Xbox One Elite 2 Controller" },	// Microsoft X-Box One Elite Series 2 pad (Bluetooth) with 5.x firmware
 	{ MAKE_CONTROLLER_ID( 0x0738, 0x4a01 ), k_eControllerType_XBoxOneController, NULL },	// Mad Catz FightStick TE 2
 	{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0139 ), k_eControllerType_XBoxOneController, "PDP Xbox One Afterglow" },	// PDP Afterglow Wired Controller for Xbox One
 	{ MAKE_CONTROLLER_ID( 0x0e6f, 0x013B ), k_eControllerType_XBoxOneController, "PDP Xbox One Face-Off Controller" },	// PDP Face-Off Gamepad for Xbox One
@@ -579,7 +580,7 @@ static const ControllerDescription_t arrControllers[] = {
 	{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0181 ), k_eControllerType_SwitchInputOnlyController, NULL },  // PDP Faceoff Deluxe Wired Pro Controller for Nintendo Switch
 	{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0184 ), k_eControllerType_SwitchInputOnlyController, NULL },  // PDP Faceoff Wired Deluxe+ Audio Controller
 	{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0185 ), k_eControllerType_SwitchInputOnlyController, NULL },  // PDP Wired Fight Pad Pro for Nintendo Switch
-	{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0186 ), k_eControllerType_SwitchProController, NULL },	// PDP Afterglow Wireless Switch Controller - working gyro. USB is for charging only. Many later "Wireless" line devices w/ gyro also use this vid/pid
+	{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0186 ), k_eControllerType_SwitchProController, NULL },        // PDP Afterglow Wireless Switch Controller - working gyro. USB is for charging only. Many later "Wireless" line devices w/ gyro also use this vid/pid
 	{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0187 ), k_eControllerType_SwitchInputOnlyController, NULL },  // PDP Rockcandy Wired Controller
 	{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0188 ), k_eControllerType_SwitchInputOnlyController, NULL },  // PDP Afterglow Wired Deluxe+ Audio Controller
 	{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00aa ), k_eControllerType_SwitchInputOnlyController, NULL },  // HORI Real Arcade Pro V Hayabusa in Switch Mode
diff --git a/src/joystick/hidapi/SDL_hidapi_xboxone.c b/src/joystick/hidapi/SDL_hidapi_xboxone.c
index ffec1c9d75..1c297f841e 100644
--- a/src/joystick/hidapi/SDL_hidapi_xboxone.c
+++ b/src/joystick/hidapi/SDL_hidapi_xboxone.c
@@ -508,12 +508,16 @@ HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne
         Paddle bits:
             P3: 0x01 (A)    P1: 0x02 (B)
             P4: 0x04 (X)    P2: 0x08 (Y)
-       Xbox One Elite Series 2 report is 38 bytes, paddles in data[18], mode in data[19], mode 0 has no mapped paddles by default
+       Xbox One Elite Series 2 4.x firmware report is 38 bytes, paddles in data[18], mode in data[19], mode 0 has no mapped paddles by default
+        Paddle bits:
+            P3: 0x04 (A)    P1: 0x01 (B)
+            P4: 0x08 (X)    P2: 0x02 (Y)
+       Xbox One Elite Series 2 5.x firmware report is 50 bytes, paddles in data[22], mode in data[23], mode 0 has no mapped paddles by default
         Paddle bits:
             P3: 0x04 (A)    P1: 0x01 (B)
             P4: 0x08 (X)    P2: 0x02 (Y)
     */
-    if (ctx->has_paddles && (size == 33 || size == 38)) {
+    if (ctx->has_paddles && (size == 33 || size == 38 || size == 50)) {
         int paddle_index;
         int button1_bit;
         int button2_bit;
@@ -532,7 +536,7 @@ HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne
             /* The mapped controller state is at offset 4, the raw state is at offset 18, compare them to see if the paddles are mapped */
             paddles_mapped = (SDL_memcmp(&data[4], &data[18], 2) != 0);
 
-        } else /* if (size == 38) */ {
+        } else if (size == 38) {
             /* XBox One Elite Series 2 */
             paddle_index = 18;
             button1_bit = 0x01;
@@ -540,6 +544,15 @@ HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne
             button3_bit = 0x04;
             button4_bit = 0x08;
             paddles_mapped = (data[19] != 0);
+
+        } else if (size == 50) {
+            /* XBox One Elite Series 2 */
+            paddle_index = 22;
+            button1_bit = 0x01;
+            button2_bit = 0x02;
+            button3_bit = 0x04;
+            button4_bit = 0x08;
+            paddles_mapped = (data[23] != 0);
         }
 #ifdef DEBUG_XBOX_PROTOCOL
         SDL_Log(">>> Paddles: %d,%d,%d,%d mapped = %s\n",
@@ -629,6 +642,7 @@ HIDAPI_DriverXboxOneBluetooth_HandleButtons16(SDL_Joystick *joystick, SDL_Driver
  * Xbox One S with firmware 4.8.1923 uses a 17 byte packet with BACK button in byte 16 and the GUIDE button in a separate packet (on Windows), or in byte 15 (on Linux)
  * Xbox One Elite Series 2 with firmware 4.7.1872 uses a 55 byte packet with BACK button in byte 16, paddles starting at byte 33, and the GUIDE button in a separate packet
  * Xbox One Elite Series 2 with firmware 4.8.1908 uses a 33 byte packet with BACK button in byte 16, paddles starting at byte 17, and the GUIDE button in a separate packet
+ * Xbox One Elite Series 2 with firmware 5.11.3112 uses a 19 byte packet with BACK and GUIDE buttons in byte 15
  * Xbox Series X with firmware 5.5.2641 uses a 17 byte packet with BACK and GUIDE buttons in byte 15, and SHARE button in byte 17
  */
 static void
@@ -644,7 +658,7 @@ HIDAPI_DriverXboxOneBluetooth_HandleButtons(SDL_Joystick *joystick, SDL_DriverXb
     }
 
     if (ctx->last_state[15] != data[15]) {
-        if (ctx->has_share_button) {
+        if (ctx->has_share_button || size == 19) {
             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[15] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[15] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
         } else if (!ctx->has_guide_packet) {
diff --git a/src/joystick/usb_ids.h b/src/joystick/usb_ids.h
index e3160c7e78..8e363a60e6 100644
--- a/src/joystick/usb_ids.h
+++ b/src/joystick/usb_ids.h
@@ -39,40 +39,41 @@
 #define USB_VENDOR_SONY         0x054c
 #define USB_VENDOR_VALVE        0x28de
 
-#define USB_PRODUCT_AMAZON_LUNA_CONTROLLER              0x0419
-#define USB_PRODUCT_GOOGLE_STADIA_CONTROLLER            0x9400
-#define USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER           0x1846
-#define USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER           0x0337
-#define USB_PRODUCT_NINTENDO_SWITCH_PRO                 0x2009
-#define USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_LEFT        0x2006
-#define USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_RIGHT       0x2007
-#define USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP        0x200e
-#define USB_PRODUCT_RAZER_PANTHERA                      0x0401
-#define USB_PRODUCT_RAZER_PANTHERA_EVO                  0x1008
-#define USB_PRODUCT_RAZER_ATROX                         0x0a00
-#define USB_PRODUCT_SONY_DS4                            0x05c4
-#define USB_PRODUCT_SONY_DS4_DONGLE                     0x0ba0
-#define USB_PRODUCT_SONY_DS4_SLIM                       0x09cc
-#define USB_PRODUCT_SONY_DS5                            0x0ce6
-#define USB_PRODUCT_XBOX360_XUSB_CONTROLLER             0x02a1    /* XUSB driver software PID */
-#define USB_PRODUCT_XBOX360_WIRED_CONTROLLER            0x028e
-#define USB_PRODUCT_XBOX360_WIRELESS_RECEIVER           0x0719
-#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1             0x02e3
-#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2             0x0b00
-#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH   0x0b05
-#define USB_PRODUCT_XBOX_ONE_S                          0x02ea
-#define USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH           0x02e0
-#define USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH           0x02fd
-#define USB_PRODUCT_XBOX_SERIES_X                       0x0b12
-#define USB_PRODUCT_XBOX_SERIES_X_BLUETOOTH             0x0b13
-#define USB_PRODUCT_XBOX_SERIES_X_VICTRIX_GAMBIT        0x02d6
-#define USB_PRODUCT_XBOX_SERIES_X_PDP_BLUE              0x02d9
-#define USB_PRODUCT_XBOX_SERIES_X_PDP_AFTERGLOW         0x02da
-#define USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO2    0x4001
-#define USB_PRODUCT_XBOX_SERIES_X_POWERA_SPECTRA        0x4002
-#define USB_PRODUCT_XBOX_ONE_XBOXGIP_CONTROLLER         0x02ff    /* XBOXGIP driver software PID */
-#define USB_PRODUCT_XBOX_ONE_XINPUT_CONTROLLER          0x02fe    /* Made up product ID for XInput */
-#define USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD               0x11ff
+#define USB_PRODUCT_AMAZON_LUNA_CONTROLLER                  0x0419
+#define USB_PRODUCT_GOOGLE_STADIA_CONTROLLER                0x9400
+#define USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER               0x1846
+#define USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER               0x0337
+#define USB_PRODUCT_NINTENDO_SWITCH_PRO                     0x2009
+#define USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_LEFT            0x2006
+#define USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_RIGHT           0x2007
+#define USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP            0x200e
+#define USB_PRODUCT_RAZER_PANTHERA                          0x0401
+#define USB_PRODUCT_RAZER_PANTHERA_EVO                      0x1008
+#define USB_PRODUCT_RAZER_ATROX                             0x0a00
+#define USB_PRODUCT_SONY_DS4                                0x05c4
+#define USB_PRODUCT_SONY_DS4_DONGLE                         0x0ba0
+#define USB_PRODUCT_SONY_DS4_SLIM                           0x09cc
+#define USB_PRODUCT_SONY_DS5                                0x0ce6
+#define USB_PRODUCT_XBOX360_XUSB_CONTROLLER                 0x02a1    /* XUSB driver software PID */
+#define USB_PRODUCT_XBOX360_WIRED_CONTROLLER                0x028e
+#define USB_PRODUCT_XBOX360_WIRELESS_RECEIVER               0x0719
+#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1                 0x02e3
+#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2                 0x0b00
+#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH       0x0b05
+#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_REV2_BLUETOOTH  0x0b22
+#define USB_PRODUCT_XBOX_ONE_S                              0x02ea
+#define USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH               0x02e0
+#define USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH               0x02fd
+#define USB_PRODUCT_XBOX_SERIES_X                           0x0b12
+#define USB_PRODUCT_XBOX_SERIES_X_BLUETOOTH                 0x0b13
+#define USB_PRODUCT_XBOX_SERIES_X_VICTRIX_GAMBIT            0x02d6
+#define USB_PRODUCT_XBOX_SERIES_X_PDP_BLUE                  0x02d9
+#define USB_PRODUCT_XBOX_SERIES_X_PDP_AFTERGLOW             0x02da
+#define USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO2        0x4001
+#define USB_PRODUCT_XBOX_SERIES_X_POWERA_SPECTRA            0x4002
+#define USB_PRODUCT_XBOX_ONE_XBOXGIP_CONTROLLER             0x02ff    /* XBOXGIP driver software PID */
+#define USB_PRODUCT_XBOX_ONE_XINPUT_CONTROLLER              0x02fe    /* Made up product ID for XInput */
+#define USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD                   0x11ff
 
 /* USB usage pages */
 #define USB_USAGEPAGE_GENERIC_DESKTOP   0x0001