diff mbox series

Input: xpad - add support for XBOX One Elite paddles

Message ID 20220417161908.138625-1-rojtberg@gmail.com (mailing list archive)
State Superseded
Headers show
Series Input: xpad - add support for XBOX One Elite paddles | expand

Commit Message

Pavel Rojtberg April 17, 2022, 4:19 p.m. UTC
From: Christopher Crockett <chaorace@gmail.com>

An effort has been made to support every official model and firmware
version I could track down info on. The following controllers _should_
have working paddles with this PR:
- Xbox Elite (**untested**)
- Xbox Elite Series 2 on early firmwares (**untested**)
- Xbox Elite Series 2 on v4 firmwares (Tested v4.8.1908.0)
- Xbox Elite Series 2 on v5 pre-BLE firmwares (**untested**)
- Xbox Elite Series 2 on v5 post-BLE firmwares (Tested v5.13.3143.0)

This patch also introduces correct handling for the Elite 1 controller
and properly suppresses paddle inputs when using a custom profile slot.

Starting in v5.11, certain inputs for the Elite 2 were moved to an extra
packet that is not enabled by default.

We must first manually enable this extra packet in order to correctly
process paddle input data with these later firmwares.

For further details see: https://github.com/paroj/xpad/pull/195

Signed-off-by: Fmstrat <nospam@nowsci.com>
Signed-off-by: Pavel Rojtberg <rojtberg@gmail.com>
---
 drivers/input/joystick/xpad.c | 239 ++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 176 insertions(+), 63 deletions(-)

Comments

Greg KH April 18, 2022, 6:20 a.m. UTC | #1
On Sun, Apr 17, 2022 at 06:19:08PM +0200, Pavel Rojtberg wrote:
> From: Christopher Crockett <chaorace@gmail.com>
> 
> An effort has been made to support every official model and firmware
> version I could track down info on. The following controllers _should_
> have working paddles with this PR:
> - Xbox Elite (**untested**)
> - Xbox Elite Series 2 on early firmwares (**untested**)
> - Xbox Elite Series 2 on v4 firmwares (Tested v4.8.1908.0)
> - Xbox Elite Series 2 on v5 pre-BLE firmwares (**untested**)
> - Xbox Elite Series 2 on v5 post-BLE firmwares (Tested v5.13.3143.0)
> 
> This patch also introduces correct handling for the Elite 1 controller
> and properly suppresses paddle inputs when using a custom profile slot.
> 
> Starting in v5.11, certain inputs for the Elite 2 were moved to an extra
> packet that is not enabled by default.

why does 5.11 matter here?

> 
> We must first manually enable this extra packet in order to correctly
> process paddle input data with these later firmwares.
> 
> For further details see: https://github.com/paroj/xpad/pull/195

don't like to random web sites, summarize in here properly.

> 
> Signed-off-by: Fmstrat <nospam@nowsci.com>

I doubt that is a correct email address and valid name :(

> Signed-off-by: Pavel Rojtberg <rojtberg@gmail.com>
> ---
>  drivers/input/joystick/xpad.c | 239 ++++++++++++++++++++++++++++++++++++++++++---------------
>  1 file changed, 176 insertions(+), 63 deletions(-)
> 
> diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
> index 53126d9..0746813 100644
> --- a/drivers/input/joystick/xpad.c
> +++ b/drivers/input/joystick/xpad.c
> @@ -80,6 +80,7 @@
>  #define MAP_TRIGGERS_TO_BUTTONS		(1 << 1)
>  #define MAP_STICKS_TO_NULL		(1 << 2)
>  #define MAP_SELECT_BUTTON		(1 << 3)
> +#define MAP_PADDLES				(1 << 4)
>  #define DANCEPAD_MAP_CONFIG	(MAP_DPAD_TO_BUTTONS |			\
>  				MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL)
>  
> @@ -89,6 +90,12 @@
>  #define XTYPE_XBOXONE     3
>  #define XTYPE_UNKNOWN     4
>  
> +#define PKT_XB              0
> +#define PKT_XBE1            1
> +#define PKT_XBE2_FW_OLD     2
> +#define PKT_XBE2_FW_5_EARLY 3
> +#define PKT_XBE2_FW_5_11    4
> +
>  static bool dpad_to_buttons;
>  module_param(dpad_to_buttons, bool, S_IRUGO);
>  MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
> @@ -111,6 +118,7 @@ static const struct xpad_device {
>  	char *name;
>  	u8 mapping;
>  	u8 xtype;
> +	u8 pktType;

Please use proper Linux kernel naming schemes.

>  } xpad_device[] = {
>  	{ 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 },
>  	{ 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX },
> @@ -128,7 +136,8 @@ static const struct xpad_device {
>  	{ 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
>  	{ 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
>  	{ 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE },
> -	{ 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", 0, XTYPE_XBOXONE },
> +	{ 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", MAP_PADDLES, XTYPE_XBOXONE },
> +	{ 0x045e, 0x0b00, "Microsoft X-Box One Elite 2 pad", MAP_PADDLES, XTYPE_XBOXONE },
>  	{ 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE },
>  	{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
>  	{ 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE },
> @@ -390,6 +399,13 @@ static const signed short xpad_abs_triggers[] = {
>  	-1
>  };
>  
> +/* used when the controller has extra paddle buttons */
> +static const signed short xpad_btn_paddles[] = {
> +	BTN_TRIGGER_HAPPY5, BTN_TRIGGER_HAPPY6, /* paddle upper right, lower right */
> +	BTN_TRIGGER_HAPPY7, BTN_TRIGGER_HAPPY8, /* paddle upper left, lower left */
> +	-1						/* terminating entry */

0 should be the terminator, right?

> +};
> +
>  /*
>   * Xbox 360 has a vendor-specific class, so we cannot match it with only
>   * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
> @@ -492,6 +508,15 @@ static const u8 xboxone_s_init[] = {
>  	0x05, 0x20, 0x00, 0x0f, 0x06
>  };
>  
> +/*
> + * This packet is required to get additional input data
> + * from Xbox One Elite Series 2 (0x045e:0x0b00) pads.
> + * We mostly do this right now to get paddle data
> + */
> +static const u8 extra_input_packet_init[] = {
> +	0x4d, 0x10, 0x01, 0x02, 0x07, 0x00
> +};
> +
>  /*
>   * This packet is required for the Titanfall 2 Xbox One pads
>   * (0x0e6f:0x0165) to finish initialization and for Hori pads
> @@ -552,6 +577,7 @@ static const struct xboxone_init_packet xboxone_init_packets[] = {
>  	XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_fw2015_init),
>  	XBOXONE_INIT_PKT(0x045e, 0x02ea, xboxone_s_init),
>  	XBOXONE_INIT_PKT(0x045e, 0x0b00, xboxone_s_init),
> +	XBOXONE_INIT_PKT(0x045e, 0x0b00, extra_input_packet_init),
>  	XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_init1),
>  	XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_init2),
>  	XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init),
> @@ -608,6 +634,7 @@ struct usb_xpad {
>  
>  	int mapping;			/* map d-pad to buttons or to axes */
>  	int xtype;			/* type of xbox device */
> +	int pktType;          /* type of the extended packet */

Again, name needs to be fixed and why no tabs like the rest of the lines
in this structure?

thanks,

greg k-h
Pavel Rojtberg April 18, 2022, 10:46 a.m. UTC | #2
Am 18.04.22 um 08:20 schrieb Greg KH:
> On Sun, Apr 17, 2022 at 06:19:08PM +0200, Pavel Rojtberg wrote:
>> From: Christopher Crockett <chaorace@gmail.com>
>>
>> An effort has been made to support every official model and firmware
>> version I could track down info on. The following controllers _should_
>> have working paddles with this PR:
>> - Xbox Elite (**untested**)
>> - Xbox Elite Series 2 on early firmwares (**untested**)
>> - Xbox Elite Series 2 on v4 firmwares (Tested v4.8.1908.0)
>> - Xbox Elite Series 2 on v5 pre-BLE firmwares (**untested**)
>> - Xbox Elite Series 2 on v5 post-BLE firmwares (Tested v5.13.3143.0)
>>
>> This patch also introduces correct handling for the Elite 1 controller
>> and properly suppresses paddle inputs when using a custom profile slot.
>>
>> Starting in v5.11, certain inputs for the Elite 2 were moved to an extra
>> packet that is not enabled by default.
> 
> why does 5.11 matter here?

This refers to the gamepad firmware, not to Linux :)

> 
>>
>> We must first manually enable this extra packet in order to correctly
>> process paddle input data with these later firmwares.
>>
>> For further details see: https://github.com/paroj/xpad/pull/195
> 
> don't like to random web sites, summarize in here properly.

The summary here should be complete. Do you have any specific questions?

The link leads to all the details i.e. the 52 entry discussion of how to read the current
firmware version etc.

> 
>>
>> Signed-off-by: Fmstrat <nospam@nowsci.com>
> 
> I doubt that is a correct email address and valid name :(

Unfortunately this is all I get at github. The only alternative would be no attribution at all.
 
>> Signed-off-by: Pavel Rojtberg <rojtberg@gmail.com>
>> ---
>>  drivers/input/joystick/xpad.c | 239 ++++++++++++++++++++++++++++++++++++++++++---------------
>>  1 file changed, 176 insertions(+), 63 deletions(-)
>>
>> diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
>> index 53126d9..0746813 100644
>> --- a/drivers/input/joystick/xpad.c
>> +++ b/drivers/input/joystick/xpad.c
>> @@ -80,6 +80,7 @@
>>  #define MAP_TRIGGERS_TO_BUTTONS		(1 << 1)
>>  #define MAP_STICKS_TO_NULL		(1 << 2)
>>  #define MAP_SELECT_BUTTON		(1 << 3)
>> +#define MAP_PADDLES				(1 << 4)
>>  #define DANCEPAD_MAP_CONFIG	(MAP_DPAD_TO_BUTTONS |			\
>>  				MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL)
>>  
>> @@ -89,6 +90,12 @@
>>  #define XTYPE_XBOXONE     3
>>  #define XTYPE_UNKNOWN     4
>>  
>> +#define PKT_XB              0
>> +#define PKT_XBE1            1
>> +#define PKT_XBE2_FW_OLD     2
>> +#define PKT_XBE2_FW_5_EARLY 3
>> +#define PKT_XBE2_FW_5_11    4
>> +
>>  static bool dpad_to_buttons;
>>  module_param(dpad_to_buttons, bool, S_IRUGO);
>>  MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
>> @@ -111,6 +118,7 @@ static const struct xpad_device {
>>  	char *name;
>>  	u8 mapping;
>>  	u8 xtype;
>> +	u8 pktType;
> 
> Please use proper Linux kernel naming schemes.

that would be pkt_type, right?

> 
>>  } xpad_device[] = {
>>  	{ 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 },
>>  	{ 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX },
>> @@ -128,7 +136,8 @@ static const struct xpad_device {
>>  	{ 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
>>  	{ 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
>>  	{ 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE },
>> -	{ 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", 0, XTYPE_XBOXONE },
>> +	{ 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", MAP_PADDLES, XTYPE_XBOXONE },
>> +	{ 0x045e, 0x0b00, "Microsoft X-Box One Elite 2 pad", MAP_PADDLES, XTYPE_XBOXONE },
>>  	{ 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE },
>>  	{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
>>  	{ 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE },
>> @@ -390,6 +399,13 @@ static const signed short xpad_abs_triggers[] = {
>>  	-1
>>  };
>>  
>> +/* used when the controller has extra paddle buttons */
>> +static const signed short xpad_btn_paddles[] = {
>> +	BTN_TRIGGER_HAPPY5, BTN_TRIGGER_HAPPY6, /* paddle upper right, lower right */
>> +	BTN_TRIGGER_HAPPY7, BTN_TRIGGER_HAPPY8, /* paddle upper left, lower left */
>> +	-1						/* terminating entry */
> 
> 0 should be the terminator, right?

while 0 would probably do, the other arrays in this file also use -1.

> 
>> +};
>> +
>>  /*
>>   * Xbox 360 has a vendor-specific class, so we cannot match it with only
>>   * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
>> @@ -492,6 +508,15 @@ static const u8 xboxone_s_init[] = {
>>  	0x05, 0x20, 0x00, 0x0f, 0x06
>>  };
>>  
>> +/*
>> + * This packet is required to get additional input data
>> + * from Xbox One Elite Series 2 (0x045e:0x0b00) pads.
>> + * We mostly do this right now to get paddle data
>> + */
>> +static const u8 extra_input_packet_init[] = {
>> +	0x4d, 0x10, 0x01, 0x02, 0x07, 0x00
>> +};
>> +
>>  /*
>>   * This packet is required for the Titanfall 2 Xbox One pads
>>   * (0x0e6f:0x0165) to finish initialization and for Hori pads
>> @@ -552,6 +577,7 @@ static const struct xboxone_init_packet xboxone_init_packets[] = {
>>  	XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_fw2015_init),
>>  	XBOXONE_INIT_PKT(0x045e, 0x02ea, xboxone_s_init),
>>  	XBOXONE_INIT_PKT(0x045e, 0x0b00, xboxone_s_init),
>> +	XBOXONE_INIT_PKT(0x045e, 0x0b00, extra_input_packet_init),
>>  	XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_init1),
>>  	XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_init2),
>>  	XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init),
>> @@ -608,6 +634,7 @@ struct usb_xpad {
>>  
>>  	int mapping;			/* map d-pad to buttons or to axes */
>>  	int xtype;			/* type of xbox device */
>> +	int pktType;          /* type of the extended packet */
> 
> Again, name needs to be fixed and why no tabs like the rest of the lines
> in this structure?

Do I read correctly, that your comments merely aiming at style mean that
you are ok with the code in general?

I can fix the style issues myself, but for code changes I would need to
reflect to Christopher, as I do not own the controller.

Greetings, Pavel

> 
> thanks,
> 
> greg k-h
Greg KH April 18, 2022, 11:25 a.m. UTC | #3
On Mon, Apr 18, 2022 at 12:46:53PM +0200, Pavel Rojtberg wrote:
> 
> 
> Am 18.04.22 um 08:20 schrieb Greg KH:
> > On Sun, Apr 17, 2022 at 06:19:08PM +0200, Pavel Rojtberg wrote:
> >> From: Christopher Crockett <chaorace@gmail.com>
> >>
> >> An effort has been made to support every official model and firmware
> >> version I could track down info on. The following controllers _should_
> >> have working paddles with this PR:
> >> - Xbox Elite (**untested**)
> >> - Xbox Elite Series 2 on early firmwares (**untested**)
> >> - Xbox Elite Series 2 on v4 firmwares (Tested v4.8.1908.0)
> >> - Xbox Elite Series 2 on v5 pre-BLE firmwares (**untested**)
> >> - Xbox Elite Series 2 on v5 post-BLE firmwares (Tested v5.13.3143.0)
> >>
> >> This patch also introduces correct handling for the Elite 1 controller
> >> and properly suppresses paddle inputs when using a custom profile slot.
> >>
> >> Starting in v5.11, certain inputs for the Elite 2 were moved to an extra
> >> packet that is not enabled by default.
> > 
> > why does 5.11 matter here?
> 
> This refers to the gamepad firmware, not to Linux :)

Ah, you should make that obvious :)

> >>
> >> We must first manually enable this extra packet in order to correctly
> >> process paddle input data with these later firmwares.
> >>
> >> For further details see: https://github.com/paroj/xpad/pull/195
> > 
> > don't like to random web sites, summarize in here properly.
> 
> The summary here should be complete. Do you have any specific questions?

If the summary is fine, no need to link to the github location, right?

> >> Signed-off-by: Fmstrat <nospam@nowsci.com>
> > 
> > I doubt that is a correct email address and valid name :(
> 
> Unfortunately this is all I get at github. The only alternative would be no attribution at all.

Did you ask?

> >> Signed-off-by: Pavel Rojtberg <rojtberg@gmail.com>
> >> ---
> >>  drivers/input/joystick/xpad.c | 239 ++++++++++++++++++++++++++++++++++++++++++---------------
> >>  1 file changed, 176 insertions(+), 63 deletions(-)
> >>
> >> diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
> >> index 53126d9..0746813 100644
> >> --- a/drivers/input/joystick/xpad.c
> >> +++ b/drivers/input/joystick/xpad.c
> >> @@ -80,6 +80,7 @@
> >>  #define MAP_TRIGGERS_TO_BUTTONS		(1 << 1)
> >>  #define MAP_STICKS_TO_NULL		(1 << 2)
> >>  #define MAP_SELECT_BUTTON		(1 << 3)
> >> +#define MAP_PADDLES				(1 << 4)
> >>  #define DANCEPAD_MAP_CONFIG	(MAP_DPAD_TO_BUTTONS |			\
> >>  				MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL)
> >>  
> >> @@ -89,6 +90,12 @@
> >>  #define XTYPE_XBOXONE     3
> >>  #define XTYPE_UNKNOWN     4
> >>  
> >> +#define PKT_XB              0
> >> +#define PKT_XBE1            1
> >> +#define PKT_XBE2_FW_OLD     2
> >> +#define PKT_XBE2_FW_5_EARLY 3
> >> +#define PKT_XBE2_FW_5_11    4
> >> +
> >>  static bool dpad_to_buttons;
> >>  module_param(dpad_to_buttons, bool, S_IRUGO);
> >>  MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
> >> @@ -111,6 +118,7 @@ static const struct xpad_device {
> >>  	char *name;
> >>  	u8 mapping;
> >>  	u8 xtype;
> >> +	u8 pktType;
> > 
> > Please use proper Linux kernel naming schemes.
> 
> that would be pkt_type, right?

You have vowels, "packet_type" is nicer.

> >>  } xpad_device[] = {
> >>  	{ 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 },
> >>  	{ 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX },
> >> @@ -128,7 +136,8 @@ static const struct xpad_device {
> >>  	{ 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
> >>  	{ 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
> >>  	{ 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE },
> >> -	{ 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", 0, XTYPE_XBOXONE },
> >> +	{ 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", MAP_PADDLES, XTYPE_XBOXONE },
> >> +	{ 0x045e, 0x0b00, "Microsoft X-Box One Elite 2 pad", MAP_PADDLES, XTYPE_XBOXONE },
> >>  	{ 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE },
> >>  	{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
> >>  	{ 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE },
> >> @@ -390,6 +399,13 @@ static const signed short xpad_abs_triggers[] = {
> >>  	-1
> >>  };
> >>  
> >> +/* used when the controller has extra paddle buttons */
> >> +static const signed short xpad_btn_paddles[] = {
> >> +	BTN_TRIGGER_HAPPY5, BTN_TRIGGER_HAPPY6, /* paddle upper right, lower right */
> >> +	BTN_TRIGGER_HAPPY7, BTN_TRIGGER_HAPPY8, /* paddle upper left, lower left */
> >> +	-1						/* terminating entry */
> > 
> > 0 should be the terminator, right?
> 
> while 0 would probably do, the other arrays in this file also use -1.

Ah, ok, nevermind.

> Do I read correctly, that your comments merely aiming at style mean that
> you are ok with the code in general?

Yes, the logic seems fine if it has been tested by others.

thanks,

greg k-h
diff mbox series

Patch

diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 53126d9..0746813 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -80,6 +80,7 @@ 
 #define MAP_TRIGGERS_TO_BUTTONS		(1 << 1)
 #define MAP_STICKS_TO_NULL		(1 << 2)
 #define MAP_SELECT_BUTTON		(1 << 3)
+#define MAP_PADDLES				(1 << 4)
 #define DANCEPAD_MAP_CONFIG	(MAP_DPAD_TO_BUTTONS |			\
 				MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL)
 
@@ -89,6 +90,12 @@ 
 #define XTYPE_XBOXONE     3
 #define XTYPE_UNKNOWN     4
 
+#define PKT_XB              0
+#define PKT_XBE1            1
+#define PKT_XBE2_FW_OLD     2
+#define PKT_XBE2_FW_5_EARLY 3
+#define PKT_XBE2_FW_5_11    4
+
 static bool dpad_to_buttons;
 module_param(dpad_to_buttons, bool, S_IRUGO);
 MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
@@ -111,6 +118,7 @@  static const struct xpad_device {
 	char *name;
 	u8 mapping;
 	u8 xtype;
+	u8 pktType;
 } xpad_device[] = {
 	{ 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 },
 	{ 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX },
@@ -128,7 +136,8 @@  static const struct xpad_device {
 	{ 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
 	{ 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
 	{ 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE },
-	{ 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", 0, XTYPE_XBOXONE },
+	{ 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", MAP_PADDLES, XTYPE_XBOXONE },
+	{ 0x045e, 0x0b00, "Microsoft X-Box One Elite 2 pad", MAP_PADDLES, XTYPE_XBOXONE },
 	{ 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE },
 	{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
 	{ 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE },
@@ -390,6 +399,13 @@  static const signed short xpad_abs_triggers[] = {
 	-1
 };
 
+/* used when the controller has extra paddle buttons */
+static const signed short xpad_btn_paddles[] = {
+	BTN_TRIGGER_HAPPY5, BTN_TRIGGER_HAPPY6, /* paddle upper right, lower right */
+	BTN_TRIGGER_HAPPY7, BTN_TRIGGER_HAPPY8, /* paddle upper left, lower left */
+	-1						/* terminating entry */
+};
+
 /*
  * Xbox 360 has a vendor-specific class, so we cannot match it with only
  * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
@@ -492,6 +508,15 @@  static const u8 xboxone_s_init[] = {
 	0x05, 0x20, 0x00, 0x0f, 0x06
 };
 
+/*
+ * This packet is required to get additional input data
+ * from Xbox One Elite Series 2 (0x045e:0x0b00) pads.
+ * We mostly do this right now to get paddle data
+ */
+static const u8 extra_input_packet_init[] = {
+	0x4d, 0x10, 0x01, 0x02, 0x07, 0x00
+};
+
 /*
  * This packet is required for the Titanfall 2 Xbox One pads
  * (0x0e6f:0x0165) to finish initialization and for Hori pads
@@ -552,6 +577,7 @@  static const struct xboxone_init_packet xboxone_init_packets[] = {
 	XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_fw2015_init),
 	XBOXONE_INIT_PKT(0x045e, 0x02ea, xboxone_s_init),
 	XBOXONE_INIT_PKT(0x045e, 0x0b00, xboxone_s_init),
+	XBOXONE_INIT_PKT(0x045e, 0x0b00, extra_input_packet_init),
 	XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_init1),
 	XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_init2),
 	XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init),
@@ -608,6 +634,7 @@  struct usb_xpad {
 
 	int mapping;			/* map d-pad to buttons or to axes */
 	int xtype;			/* type of xbox device */
+	int pktType;          /* type of the extended packet */
 	int pad_nr;			/* the order x360 pads were attached */
 	const char *name;		/* name of the device */
 	struct work_struct work;	/* init/remove device from callback */
@@ -846,6 +873,7 @@  static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha
 static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
 {
 	struct input_dev *dev = xpad->dev;
+	bool do_sync = false;
 
 	/* the xbox button has its own special report */
 	if (data[0] == 0X07) {
@@ -858,75 +886,133 @@  static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char
 			xpadone_ack_mode_report(xpad, data[2]);
 
 		input_report_key(dev, BTN_MODE, data[4] & 0x01);
-		input_sync(dev);
-		return;
-	}
-	/* check invalid packet */
-	else if (data[0] != 0X20)
-		return;
-
-	/* menu/view buttons */
-	input_report_key(dev, BTN_START,  data[4] & 0x04);
-	input_report_key(dev, BTN_SELECT, data[4] & 0x08);
-	if (xpad->mapping & MAP_SELECT_BUTTON)
-		input_report_key(dev, KEY_RECORD, data[22] & 0x01);
 
-	/* buttons A,B,X,Y */
-	input_report_key(dev, BTN_A,	data[4] & 0x10);
-	input_report_key(dev, BTN_B,	data[4] & 0x20);
-	input_report_key(dev, BTN_X,	data[4] & 0x40);
-	input_report_key(dev, BTN_Y,	data[4] & 0x80);
-
-	/* digital pad */
-	if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
-		/* dpad as buttons (left, right, up, down) */
-		input_report_key(dev, BTN_TRIGGER_HAPPY1, data[5] & 0x04);
-		input_report_key(dev, BTN_TRIGGER_HAPPY2, data[5] & 0x08);
-		input_report_key(dev, BTN_TRIGGER_HAPPY3, data[5] & 0x01);
-		input_report_key(dev, BTN_TRIGGER_HAPPY4, data[5] & 0x02);
-	} else {
-		input_report_abs(dev, ABS_HAT0X,
-				 !!(data[5] & 0x08) - !!(data[5] & 0x04));
-		input_report_abs(dev, ABS_HAT0Y,
-				 !!(data[5] & 0x02) - !!(data[5] & 0x01));
-	}
-
-	/* TL/TR */
-	input_report_key(dev, BTN_TL,	data[5] & 0x10);
-	input_report_key(dev, BTN_TR,	data[5] & 0x20);
+		do_sync = true;
+	} else if (data[0] == 0X0C) {
+		/* Some packet formats force us to use this separate to poll paddle inputs */
+		if (xpad->pktType == PKT_XBE2_FW_5_11) {
+			/* Mute paddles if controller is in a custom profile slot */
+			/* Checked by looking at the active profile slot to verify it's the default slot */
+			if (data[19] != 0) {
+				data[18] = 0;
+			}
+
+			/* Elite Series 2 split packet paddle bits */
+			input_report_key(dev, BTN_TRIGGER_HAPPY5, data[18] & 0x01);
+			input_report_key(dev, BTN_TRIGGER_HAPPY6, data[18] & 0x02);
+			input_report_key(dev, BTN_TRIGGER_HAPPY7, data[18] & 0x04);
+			input_report_key(dev, BTN_TRIGGER_HAPPY8, data[18] & 0x08);
+
+			do_sync = true;
+		}
+	} else if (data[0] == 0X20) { /* The main valid packet type for inputs */
+		/* menu/view buttons */
+		input_report_key(dev, BTN_START,  data[4] & 0x04);
+		input_report_key(dev, BTN_SELECT, data[4] & 0x08);
+		if (xpad->mapping & MAP_SELECT_BUTTON)
+			input_report_key(dev, KEY_RECORD, data[22] & 0x01);
+
+		/* buttons A,B,X,Y */
+		input_report_key(dev, BTN_A,	data[4] & 0x10);
+		input_report_key(dev, BTN_B,	data[4] & 0x20);
+		input_report_key(dev, BTN_X,	data[4] & 0x40);
+		input_report_key(dev, BTN_Y,	data[4] & 0x80);
+
+		/* digital pad */
+		if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
+			/* dpad as buttons (left, right, up, down) */
+			input_report_key(dev, BTN_TRIGGER_HAPPY1, data[5] & 0x04);
+			input_report_key(dev, BTN_TRIGGER_HAPPY2, data[5] & 0x08);
+			input_report_key(dev, BTN_TRIGGER_HAPPY3, data[5] & 0x01);
+			input_report_key(dev, BTN_TRIGGER_HAPPY4, data[5] & 0x02);
+		} else {
+			input_report_abs(dev, ABS_HAT0X,
+					!!(data[5] & 0x08) - !!(data[5] & 0x04));
+			input_report_abs(dev, ABS_HAT0Y,
+					!!(data[5] & 0x02) - !!(data[5] & 0x01));
+		}
 
-	/* stick press left/right */
-	input_report_key(dev, BTN_THUMBL, data[5] & 0x40);
-	input_report_key(dev, BTN_THUMBR, data[5] & 0x80);
+		/* TL/TR */
+		input_report_key(dev, BTN_TL,	data[5] & 0x10);
+		input_report_key(dev, BTN_TR,	data[5] & 0x20);
+
+		/* stick press left/right */
+		input_report_key(dev, BTN_THUMBL, data[5] & 0x40);
+		input_report_key(dev, BTN_THUMBR, data[5] & 0x80);
+
+		if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+			/* left stick */
+			input_report_abs(dev, ABS_X,
+					(__s16) le16_to_cpup((__le16 *)(data + 10)));
+			input_report_abs(dev, ABS_Y,
+					~(__s16) le16_to_cpup((__le16 *)(data + 12)));
+
+			/* right stick */
+			input_report_abs(dev, ABS_RX,
+					(__s16) le16_to_cpup((__le16 *)(data + 14)));
+			input_report_abs(dev, ABS_RY,
+					~(__s16) le16_to_cpup((__le16 *)(data + 16)));
+		}
 
-	if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
-		/* left stick */
-		input_report_abs(dev, ABS_X,
-				 (__s16) le16_to_cpup((__le16 *)(data + 10)));
-		input_report_abs(dev, ABS_Y,
-				 ~(__s16) le16_to_cpup((__le16 *)(data + 12)));
+		/* triggers left/right */
+		if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
+			input_report_key(dev, BTN_TL2,
+					(__u16) le16_to_cpup((__le16 *)(data + 6)));
+			input_report_key(dev, BTN_TR2,
+					(__u16) le16_to_cpup((__le16 *)(data + 8)));
+		} else {
+			input_report_abs(dev, ABS_Z,
+					(__u16) le16_to_cpup((__le16 *)(data + 6)));
+			input_report_abs(dev, ABS_RZ,
+					(__u16) le16_to_cpup((__le16 *)(data + 8)));
+		}
 
-		/* right stick */
-		input_report_abs(dev, ABS_RX,
-				 (__s16) le16_to_cpup((__le16 *)(data + 14)));
-		input_report_abs(dev, ABS_RY,
-				 ~(__s16) le16_to_cpup((__le16 *)(data + 16)));
-	}
+		/* paddle handling */
+		/* based on SDL's SDL_hidapi_xboxone.c */
+		if (xpad->mapping & MAP_PADDLES) {
+			if (xpad->pktType == PKT_XBE1){
+				/* Mute paddles if controller has a custom mapping applied */
+				/* Checked by comparing the current mapping config against the factory mapping config */
+				if (memcmp(&data[4], &data[18], 2) != 0) {
+					data[32] = 0;
+				}
+				/* OG Elite Series Controller paddle bits */
+				input_report_key(dev, BTN_TRIGGER_HAPPY5, data[32] & 0x02);
+				input_report_key(dev, BTN_TRIGGER_HAPPY6, data[32] & 0x08);
+				input_report_key(dev, BTN_TRIGGER_HAPPY7, data[32] & 0x01);
+				input_report_key(dev, BTN_TRIGGER_HAPPY8, data[32] & 0x04);
+			} else if (xpad->pktType == PKT_XBE2_FW_OLD){
+				/* Mute paddles if controller is in a custom profile slot */
+				/* Checked by looking at the active profile slot to verify it's the default slot */
+				if (data[19] != 0) {
+					data[18] = 0;
+				}
+
+				/* Elite Series 2 4.x firmware paddle bits */
+				input_report_key(dev, BTN_TRIGGER_HAPPY5, data[18] & 0x01);
+				input_report_key(dev, BTN_TRIGGER_HAPPY6, data[18] & 0x02);
+				input_report_key(dev, BTN_TRIGGER_HAPPY7, data[18] & 0x04);
+				input_report_key(dev, BTN_TRIGGER_HAPPY8, data[18] & 0x08);
+			} else if (xpad->pktType == PKT_XBE2_FW_5_EARLY){
+				/* Mute paddles if controller is in a custom profile slot */
+				/* Checked by looking at the active profile slot to verify it's the default slot */
+				if (data[23] != 0) {
+					data[22] = 0;
+				}
+
+				/* Elite Series 2 5.x firmware paddle bits (before the packet was split) */
+				input_report_key(dev, BTN_TRIGGER_HAPPY5, data[22] & 0x01);
+				input_report_key(dev, BTN_TRIGGER_HAPPY6, data[22] & 0x02);
+				input_report_key(dev, BTN_TRIGGER_HAPPY7, data[22] & 0x04);
+				input_report_key(dev, BTN_TRIGGER_HAPPY8, data[22] & 0x08);
+			}
+		}
 
-	/* triggers left/right */
-	if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
-		input_report_key(dev, BTN_TL2,
-				 (__u16) le16_to_cpup((__le16 *)(data + 6)));
-		input_report_key(dev, BTN_TR2,
-				 (__u16) le16_to_cpup((__le16 *)(data + 8)));
-	} else {
-		input_report_abs(dev, ABS_Z,
-				 (__u16) le16_to_cpup((__le16 *)(data + 6)));
-		input_report_abs(dev, ABS_RZ,
-				 (__u16) le16_to_cpup((__le16 *)(data + 8)));
+		do_sync = true;
 	}
 
-	input_sync(dev);
+	if (do_sync)
+		input_sync(dev);
 }
 
 static void xpad_irq_in(struct urb *urb)
@@ -1693,6 +1779,12 @@  static int xpad_init_input(struct usb_xpad *xpad)
 					     xpad_btn_pad[i]);
 	}
 
+	/* set up paddles if the controller has them */
+	if (xpad->mapping & MAP_PADDLES) {
+		for (i = 0; xpad_btn_paddles[i] >= 0; i++)
+			input_set_capability(input_dev, EV_KEY, xpad_btn_paddles[i]);
+	}
+
 	/*
 	 * This should be a simple else block. However historically
 	 * xbox360w has mapped DPAD to buttons while xbox360 did not. This
@@ -1779,6 +1871,7 @@  static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 	xpad->mapping = xpad_device[i].mapping;
 	xpad->xtype = xpad_device[i].xtype;
 	xpad->name = xpad_device[i].name;
+	xpad->pktType = PKT_XB;
 	INIT_WORK(&xpad->work, xpad_presence_work);
 
 	if (xpad->xtype == XTYPE_UNKNOWN) {
@@ -1844,6 +1937,26 @@  static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 
 	usb_set_intfdata(intf, xpad);
 
+	/* Packet type detection */
+	if (le16_to_cpu(udev->descriptor.idVendor) == 0x045e) { /* Microsoft controllers */
+		if (le16_to_cpu(udev->descriptor.idProduct) == 0x02e3) { /* Elite 1 controller */
+			/* The original elite controller always uses the oldest type of extended packet */
+			xpad->pktType = PKT_XBE1;
+		} else if (le16_to_cpu(udev->descriptor.idProduct) == 0x0b00) { /* Elite 2 controller */
+			/* The elite 2 controller has seen multiple packet revisions. These are tied to specific firmware versions */
+			if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x0500) {
+				/* This is the format that the Elite 2 used prior to the BLE update */
+				xpad->pktType = PKT_XBE2_FW_OLD;
+			} else if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x050b) {
+				/* This is the format that the Elite 2 used prior to the update that split the packet */
+				xpad->pktType = PKT_XBE2_FW_5_EARLY;
+			} else {
+				/* The split packet format that was introduced in v5.11 */
+				xpad->pktType = PKT_XBE2_FW_5_11;
+			}
+		}
+	}
+
 	if (xpad->xtype == XTYPE_XBOX360W) {
 		/*
 		 * Submit the int URB immediately rather than waiting for open