diff options
author | Cameron Gutman <aicommander@gmail.com> | 2017-04-10 23:43:04 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2017-04-10 23:45:14 -0400 |
commit | 81093c9848a781b85163d06de92ef8f84528cf6a (patch) | |
tree | 4a98d49a601cf21fa0334e02114f3ca34bac382e | |
parent | c5cb37d0d62c58320f0a86777b738fb28272245b (diff) |
Input: xpad - support some quirky Xbox One pads
There are several quirky Xbox One pads that depend on initialization
packets that the Microsoft pads don't require. To deal with these,
I've added a mechanism for issuing device-specific initialization
packets using a VID/PID-based quirks list.
For the initial set of init quirks, I have added quirk handling from
Valve's Steam Link xpad driver[0] and the 360Controller project[1] for
macOS to enable some new pads to work properly.
This should enable full functionality on the following quirky pads:
0x0e6f:0x0165 - Titanfall 2 gamepad (previously fully non-functional)
0x0f0d:0x0067 - Hori Horipad (analog sticks previously non-functional)
0x24c6:0x541a - PowerA Xbox One pad (previously fully non-functional)
0x24c6:0x542a - PowerA Xbox One pad (previously fully non-functional)
0x24c6:0x543a - PowerA Xbox One pad (previously fully non-functional)
[0]: https://github.com/ValveSoftware/steamlink-sdk/blob/master/kernel/drivers/input/joystick/xpad.c
[1]: https://github.com/360Controller/360Controller
Signed-off-by: Cameron Gutman <aicommander@gmail.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r-- | drivers/input/joystick/xpad.c | 114 |
1 files changed, 101 insertions, 13 deletions
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 155fcb3b6230..8a41926dab0a 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c | |||
@@ -337,6 +337,64 @@ static struct usb_device_id xpad_table[] = { | |||
337 | 337 | ||
338 | MODULE_DEVICE_TABLE(usb, xpad_table); | 338 | MODULE_DEVICE_TABLE(usb, xpad_table); |
339 | 339 | ||
340 | struct xboxone_init_packet { | ||
341 | u16 idVendor; | ||
342 | u16 idProduct; | ||
343 | const u8 *data; | ||
344 | u8 len; | ||
345 | }; | ||
346 | |||
347 | #define XBOXONE_INIT_PKT(_vid, _pid, _data) \ | ||
348 | { \ | ||
349 | .idVendor = (_vid), \ | ||
350 | .idProduct = (_pid), \ | ||
351 | .data = (_data), \ | ||
352 | .len = ARRAY_SIZE(_data), \ | ||
353 | } | ||
354 | |||
355 | |||
356 | /* | ||
357 | * This packet is required for all Xbox One pads with 2015 | ||
358 | * or later firmware installed (or present from the factory). | ||
359 | */ | ||
360 | static const u8 xboxone_fw2015_init[] = { | ||
361 | 0x05, 0x20, 0x00, 0x01, 0x00 | ||
362 | }; | ||
363 | |||
364 | /* | ||
365 | * This packet is required for the Titanfall 2 Xbox One pads | ||
366 | * (0x0e6f:0x0165) to finish initialization and for Hori pads | ||
367 | * (0x0f0d:0x0067) to make the analog sticks work. | ||
368 | */ | ||
369 | static const u8 xboxone_hori_init[] = { | ||
370 | 0x01, 0x20, 0x00, 0x09, 0x00, 0x04, 0x20, 0x3a, | ||
371 | 0x00, 0x00, 0x00, 0x80, 0x00 | ||
372 | }; | ||
373 | |||
374 | /* | ||
375 | * A rumble packet is required for some PowerA pads to start | ||
376 | * sending input reports. One of those pads is (0x24c6:0x543a). | ||
377 | */ | ||
378 | static const u8 xboxone_zerorumble_init[] = { | ||
379 | 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, | ||
380 | 0x00, 0x00, 0x00, 0x00, 0x00 | ||
381 | }; | ||
382 | |||
383 | /* | ||
384 | * This specifies the selection of init packets that a gamepad | ||
385 | * will be sent on init *and* the order in which they will be | ||
386 | * sent. The correct sequence number will be added when the | ||
387 | * packet is going to be sent. | ||
388 | */ | ||
389 | static const struct xboxone_init_packet xboxone_init_packets[] = { | ||
390 | XBOXONE_INIT_PKT(0x0e6f, 0x0165, xboxone_hori_init), | ||
391 | XBOXONE_INIT_PKT(0x0f0d, 0x0067, xboxone_hori_init), | ||
392 | XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_fw2015_init), | ||
393 | XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_zerorumble_init), | ||
394 | XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_zerorumble_init), | ||
395 | XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_zerorumble_init), | ||
396 | }; | ||
397 | |||
340 | struct xpad_output_packet { | 398 | struct xpad_output_packet { |
341 | u8 data[XPAD_PKT_LEN]; | 399 | u8 data[XPAD_PKT_LEN]; |
342 | u8 len; | 400 | u8 len; |
@@ -373,6 +431,7 @@ struct usb_xpad { | |||
373 | 431 | ||
374 | struct xpad_output_packet out_packets[XPAD_NUM_OUT_PACKETS]; | 432 | struct xpad_output_packet out_packets[XPAD_NUM_OUT_PACKETS]; |
375 | int last_out_packet; | 433 | int last_out_packet; |
434 | int init_seq; | ||
376 | 435 | ||
377 | #if defined(CONFIG_JOYSTICK_XPAD_LEDS) | 436 | #if defined(CONFIG_JOYSTICK_XPAD_LEDS) |
378 | struct xpad_led *led; | 437 | struct xpad_led *led; |
@@ -748,11 +807,47 @@ exit: | |||
748 | } | 807 | } |
749 | 808 | ||
750 | /* Callers must hold xpad->odata_lock spinlock */ | 809 | /* Callers must hold xpad->odata_lock spinlock */ |
810 | static bool xpad_prepare_next_init_packet(struct usb_xpad *xpad) | ||
811 | { | ||
812 | const struct xboxone_init_packet *init_packet; | ||
813 | |||
814 | if (xpad->xtype != XTYPE_XBOXONE) | ||
815 | return false; | ||
816 | |||
817 | /* Perform initialization sequence for Xbox One pads that require it */ | ||
818 | while (xpad->init_seq < ARRAY_SIZE(xboxone_init_packets)) { | ||
819 | init_packet = &xboxone_init_packets[xpad->init_seq++]; | ||
820 | |||
821 | if (init_packet->idVendor != 0 && | ||
822 | init_packet->idVendor != xpad->dev->id.vendor) | ||
823 | continue; | ||
824 | |||
825 | if (init_packet->idProduct != 0 && | ||
826 | init_packet->idProduct != xpad->dev->id.product) | ||
827 | continue; | ||
828 | |||
829 | /* This packet applies to our device, so prepare to send it */ | ||
830 | memcpy(xpad->odata, init_packet->data, init_packet->len); | ||
831 | xpad->irq_out->transfer_buffer_length = init_packet->len; | ||
832 | |||
833 | /* Update packet with current sequence number */ | ||
834 | xpad->odata[2] = xpad->odata_serial++; | ||
835 | return true; | ||
836 | } | ||
837 | |||
838 | return false; | ||
839 | } | ||
840 | |||
841 | /* Callers must hold xpad->odata_lock spinlock */ | ||
751 | static bool xpad_prepare_next_out_packet(struct usb_xpad *xpad) | 842 | static bool xpad_prepare_next_out_packet(struct usb_xpad *xpad) |
752 | { | 843 | { |
753 | struct xpad_output_packet *pkt, *packet = NULL; | 844 | struct xpad_output_packet *pkt, *packet = NULL; |
754 | int i; | 845 | int i; |
755 | 846 | ||
847 | /* We may have init packets to send before we can send user commands */ | ||
848 | if (xpad_prepare_next_init_packet(xpad)) | ||
849 | return true; | ||
850 | |||
756 | for (i = 0; i < XPAD_NUM_OUT_PACKETS; i++) { | 851 | for (i = 0; i < XPAD_NUM_OUT_PACKETS; i++) { |
757 | if (++xpad->last_out_packet >= XPAD_NUM_OUT_PACKETS) | 852 | if (++xpad->last_out_packet >= XPAD_NUM_OUT_PACKETS) |
758 | xpad->last_out_packet = 0; | 853 | xpad->last_out_packet = 0; |
@@ -938,24 +1033,17 @@ static int xpad_inquiry_pad_presence(struct usb_xpad *xpad) | |||
938 | 1033 | ||
939 | static int xpad_start_xbox_one(struct usb_xpad *xpad) | 1034 | static int xpad_start_xbox_one(struct usb_xpad *xpad) |
940 | { | 1035 | { |
941 | struct xpad_output_packet *packet = | ||
942 | &xpad->out_packets[XPAD_OUT_CMD_IDX]; | ||
943 | unsigned long flags; | 1036 | unsigned long flags; |
944 | int retval; | 1037 | int retval; |
945 | 1038 | ||
946 | spin_lock_irqsave(&xpad->odata_lock, flags); | 1039 | spin_lock_irqsave(&xpad->odata_lock, flags); |
947 | 1040 | ||
948 | /* Xbox one controller needs to be initialized. */ | 1041 | /* |
949 | packet->data[0] = 0x05; | 1042 | * Begin the init sequence by attempting to send a packet. |
950 | packet->data[1] = 0x20; | 1043 | * We will cycle through the init packet sequence before |
951 | packet->data[2] = xpad->odata_serial++; /* packet serial */ | 1044 | * sending any packets from the output ring. |
952 | packet->data[3] = 0x01; /* rumble bit enable? */ | 1045 | */ |
953 | packet->data[4] = 0x00; | 1046 | xpad->init_seq = 0; |
954 | packet->len = 5; | ||
955 | packet->pending = true; | ||
956 | |||
957 | /* Reset the sequence so we send out start packet first */ | ||
958 | xpad->last_out_packet = -1; | ||
959 | retval = xpad_try_sending_next_out_packet(xpad); | 1047 | retval = xpad_try_sending_next_out_packet(xpad); |
960 | 1048 | ||
961 | spin_unlock_irqrestore(&xpad->odata_lock, flags); | 1049 | spin_unlock_irqrestore(&xpad->odata_lock, flags); |