src/joystick/hidapi/SDL_hidapi_xboxone.c
author Sam Lantinga
Mon, 16 Dec 2019 10:20:03 -0800
changeset 13348 448528dc13da
parent 13344 0532eba8e423
child 13354 8c22865bd138
permissions -rw-r--r--
Fixed bug 4898 - No rumble because of integer overflow in SDL_JoystickRumble

meyraud705

On a Dualshock 4 controller using hidapi driver, calling SDL_JoystickRumble with a duration too long (SDL_HAPTIC_INFINITY for example) causes the rumble to stop immediately.

This happens because of integer overflow on line 301 of SDL_hidapi_ps4.c
(https://hg.libsdl.org/SDL/file/99ecd178999f/src/joystick/hidapi/SDL_hidapi_ps4.c#l301), which sets expiration time in the past.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #ifdef SDL_JOYSTICK_HIDAPI
    24 
    25 #include "SDL_hints.h"
    26 #include "SDL_log.h"
    27 #include "SDL_events.h"
    28 #include "SDL_timer.h"
    29 #include "SDL_joystick.h"
    30 #include "SDL_gamecontroller.h"
    31 #include "../SDL_sysjoystick.h"
    32 #include "SDL_hidapijoystick_c.h"
    33 
    34 
    35 #ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
    36 
    37 #define USB_PACKET_LENGTH   64
    38 
    39 /* The amount of time to wait after hotplug to send controller init sequence */
    40 #define CONTROLLER_INIT_DELAY_MS    100
    41 
    42 /* This is the full init sequence for the Xbox One Elite Series 2 controller.
    43    Normally it isn't needed, but this switches the controller back to wired report mode after being in Bluetooth mode.
    44 */
    45 static const Uint8 xboxone_elite_init0[] = {
    46     0x04, 0x20, 0x01, 0x00
    47 };
    48 static const Uint8 xboxone_elite_init1[] = {
    49     0x01, 0x20, 0x28, 0x09, 0x00, 0x04, 0x20, 0x3A,
    50     0x00, 0x00, 0x00, 0x31, 0x01
    51 };
    52 static const Uint8 xboxone_elite_init2[] = {
    53     0x01, 0x20, 0x28, 0x09, 0x00, 0x04, 0x20, 0x6B,
    54     0x01, 0x00, 0x00, 0x00, 0x00
    55 };
    56 static const Uint8 xboxone_elite_init3[] = {
    57     0x05, 0x20, 0x02, 0x0F, 0x06, 0x00, 0x00, 0x00,
    58     0x00, 0x00, 0x00, 0x55, 0x53, 0x00, 0x00, 0x00,
    59     0x00, 0x00, 0x00
    60 };
    61 static const Uint8 xboxone_elite_init4[] = {
    62     0x05, 0x20, 0x03, 0x01, 0x00
    63 };
    64 static const Uint8 xboxone_elite_init5[] = {
    65     0x0A, 0x20, 0x04, 0x03, 0x00, 0x01, 0x14
    66 };
    67 
    68 /*
    69  * This packet is required for all Xbox One pads with 2015
    70  * or later firmware installed (or present from the factory).
    71  */
    72 static const Uint8 xboxone_fw2015_init[] = {
    73     0x05, 0x20, 0x00, 0x01, 0x00
    74 };
    75 
    76 /*
    77  * This packet turns on the LED on some controllers, including PowerA
    78  */
    79 static const Uint8 xboxone_led_enable[] = {
    80     0x0A, 0x20, 0x04, 0x03, 0x00, 0x01, 0x14
    81 };
    82 
    83 /*
    84  * This packet is required for the Titanfall 2 Xbox One pads
    85  * (0x0e6f:0x0165) to finish initialization and for Hori pads
    86  * (0x0f0d:0x0067) to make the analog sticks work.
    87  */
    88 static const Uint8 xboxone_hori_init[] = {
    89     0x01, 0x20, 0x00, 0x09, 0x00, 0x04, 0x20, 0x3a,
    90     0x00, 0x00, 0x00, 0x80, 0x00
    91 };
    92 
    93 /*
    94  * This packet is required for some of the PDP pads to start
    95  * sending input reports. These pads include: (0x0e6f:0x02ab),
    96  * (0x0e6f:0x02a4).
    97  */
    98 static const Uint8 xboxone_pdp_init1[] = {
    99     0x0a, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14
   100 };
   101 
   102 /*
   103  * This packet is required for some of the PDP pads to start
   104  * sending input reports. These pads include: (0x0e6f:0x02ab),
   105  * (0x0e6f:0x02a4).
   106  */
   107 static const Uint8 xboxone_pdp_init2[] = {
   108     0x06, 0x20, 0x00, 0x02, 0x01, 0x00
   109 };
   110 
   111 /*
   112  * A specific rumble packet is required for some PowerA pads to start
   113  * sending input reports. One of those pads is (0x24c6:0x543a).
   114  */
   115 static const Uint8 xboxone_rumblebegin_init[] = {
   116     0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
   117     0x1D, 0x1D, 0xFF, 0x00, 0x00
   118 };
   119 
   120 /*
   121  * A rumble packet with zero FF intensity will immediately
   122  * terminate the rumbling required to init PowerA pads.
   123  * This should happen fast enough that the motors don't
   124  * spin up to enough speed to actually vibrate the gamepad.
   125  */
   126 static const Uint8 xboxone_rumbleend_init[] = {
   127     0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
   128     0x00, 0x00, 0x00, 0x00, 0x00
   129 };
   130 
   131 /*
   132  * This specifies the selection of init packets that a gamepad
   133  * will be sent on init *and* the order in which they will be
   134  * sent. The correct sequence number will be added when the
   135  * packet is going to be sent.
   136  */
   137 typedef struct {
   138     Uint16 vendor_id;
   139     Uint16 product_id;
   140     const Uint8 *data;
   141     int size;
   142 } SDL_DriverXboxOne_InitPacket;
   143 
   144 
   145 static const SDL_DriverXboxOne_InitPacket xboxone_init_packets[] = {
   146     { 0x0e6f, 0x0165, xboxone_hori_init, sizeof(xboxone_hori_init) },
   147     { 0x0f0d, 0x0067, xboxone_hori_init, sizeof(xboxone_hori_init) },
   148     { 0x045e, 0x0b00, xboxone_elite_init0, sizeof(xboxone_elite_init0) },
   149     { 0x045e, 0x0b00, xboxone_elite_init1, sizeof(xboxone_elite_init1) },
   150     { 0x045e, 0x0b00, xboxone_elite_init2, sizeof(xboxone_elite_init2) },
   151     { 0x045e, 0x0b00, xboxone_elite_init3, sizeof(xboxone_elite_init3) },
   152     { 0x045e, 0x0b00, xboxone_elite_init4, sizeof(xboxone_elite_init4) },
   153     { 0x045e, 0x0b00, xboxone_elite_init5, sizeof(xboxone_elite_init5) },
   154     { 0x0000, 0x0000, xboxone_fw2015_init, sizeof(xboxone_fw2015_init) },
   155     { 0x0000, 0x0000, xboxone_led_enable, sizeof(xboxone_led_enable) },
   156     { 0x0e6f, 0x0000, xboxone_pdp_init1, sizeof(xboxone_pdp_init1) },
   157     { 0x0e6f, 0x0000, xboxone_pdp_init2, sizeof(xboxone_pdp_init2) },
   158     { 0x24c6, 0x0000, xboxone_rumblebegin_init, sizeof(xboxone_rumblebegin_init) },
   159     { 0x24c6, 0x0000, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init) },
   160 };
   161 
   162 typedef struct {
   163     Uint16 vendor_id;
   164     Uint16 product_id;
   165     Uint32 start_time;
   166     SDL_bool initialized;
   167     Uint8 sequence;
   168     Uint8 last_state[USB_PACKET_LENGTH];
   169     Uint32 rumble_expiration;
   170 } SDL_DriverXboxOne_Context;
   171 
   172 
   173 static SDL_bool
   174 IsBluetoothXboxOneController(Uint16 vendor_id, Uint16 product_id)
   175 {
   176     /* Check to see if it's the Xbox One S or Xbox One Elite Series 2 in Bluetooth mode */
   177     const Uint16 USB_VENDOR_MICROSOFT = 0x045e;
   178     const Uint16 USB_PRODUCT_XBOX_ONE_S_REV1 = 0x02e0;
   179     const Uint16 USB_PRODUCT_XBOX_ONE_S_REV2 = 0x02fd;
   180     const Uint16 USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2 = 0x0b05;
   181 
   182     if (vendor_id == USB_VENDOR_MICROSOFT) {
   183         if (product_id == USB_PRODUCT_XBOX_ONE_S_REV1 ||
   184             product_id == USB_PRODUCT_XBOX_ONE_S_REV2 ||
   185             product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2) {
   186             return SDL_TRUE;
   187         }
   188     }
   189     return SDL_FALSE;
   190 }
   191 
   192 static SDL_bool
   193 SendControllerInit(hid_device *dev, SDL_DriverXboxOne_Context *ctx)
   194 {
   195     Uint16 vendor_id = ctx->vendor_id;
   196     Uint16 product_id = ctx->product_id;
   197 
   198     if (!IsBluetoothXboxOneController(vendor_id, product_id)) {
   199         int i, j;
   200         Uint8 init_packet[USB_PACKET_LENGTH];
   201 
   202         for (i = 0; i < SDL_arraysize(xboxone_init_packets); ++i) {
   203             const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[i];
   204 
   205             if (packet->vendor_id && (vendor_id != packet->vendor_id)) {
   206                 continue;
   207             }
   208 
   209             if (packet->product_id && (product_id != packet->product_id)) {
   210                 continue;
   211             }
   212 
   213             SDL_memcpy(init_packet, packet->data, packet->size);
   214             init_packet[2] = ctx->sequence++;
   215             if (hid_write(dev, init_packet, packet->size) != packet->size) {
   216                 SDL_SetError("Couldn't write Xbox One initialization packet");
   217                 return SDL_FALSE;
   218             }
   219 
   220             /* After the init we need to sync up the rumble sequence */
   221             if (packet->data == xboxone_fw2015_init) {
   222                 for (j = 0; j < 255; ++j) {
   223                     if (hid_write(dev, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init)) != sizeof(xboxone_rumbleend_init)) {
   224                         SDL_SetError("Couldn't write Xbox One initialization packet");
   225                         return SDL_FALSE;
   226                     }
   227                 }
   228             }
   229         }
   230     }
   231     return SDL_TRUE;
   232 }
   233 
   234 
   235 static SDL_bool
   236 HIDAPI_DriverXboxOne_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name)
   237 {
   238 #ifdef __LINUX__
   239     if (IsBluetoothXboxOneController(vendor_id, product_id)) {
   240         /* We can't do rumble on this device, hid_write() fails, so don't try to open it here */
   241         return SDL_FALSE;
   242     }
   243     if (vendor_id == 0x24c6 && product_id == 0x541a) {
   244         /* The PowerA Mini controller, model 1240245-01, blocks while writing feature reports */
   245         return SDL_FALSE;
   246     }
   247 #endif
   248     return (SDL_GetJoystickGameControllerType(vendor_id, product_id, name) == SDL_CONTROLLER_TYPE_XBOXONE);
   249 }
   250 
   251 static const char *
   252 HIDAPI_DriverXboxOne_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
   253 {
   254     return NULL;
   255 }
   256 
   257 static SDL_bool
   258 HIDAPI_DriverXboxOne_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
   259 {
   260     SDL_DriverXboxOne_Context *ctx;
   261 
   262     ctx = (SDL_DriverXboxOne_Context *)SDL_calloc(1, sizeof(*ctx));
   263     if (!ctx) {
   264         SDL_OutOfMemory();
   265         return SDL_FALSE;
   266     }
   267     *context = ctx;
   268 
   269     ctx->vendor_id = vendor_id;
   270     ctx->product_id = product_id;
   271     ctx->start_time = SDL_GetTicks();
   272 
   273     /* Initialize the joystick capabilities */
   274     joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
   275     joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
   276     joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
   277 
   278     return SDL_TRUE;
   279 }
   280 
   281 static int
   282 HIDAPI_DriverXboxOne_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   283 {
   284     SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
   285     Uint8 rumble_packet[] = { 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF };
   286 
   287     if (!ctx->initialized) {
   288         return 0;
   289     }
   290 
   291     /* Magnitude is 1..100 so scale the 16-bit input here */
   292     rumble_packet[2] = ctx->sequence++;
   293     rumble_packet[8] = low_frequency_rumble / 655;
   294     rumble_packet[9] = high_frequency_rumble / 655;
   295 
   296     if (hid_write(dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
   297         return SDL_SetError("Couldn't send rumble packet");
   298     }
   299 
   300     if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
   301         ctx->rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
   302     } else {
   303         ctx->rumble_expiration = 0;
   304     }
   305     return 0;
   306 }
   307 
   308 static void
   309 HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
   310 {
   311     Sint16 axis;
   312 
   313     if (ctx->last_state[4] != data[4]) {
   314         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[4] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   315         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[4] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   316         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[4] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   317         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[4] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   318         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[4] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   319         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[4] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   320     }
   321 
   322     if (ctx->last_state[5] != data[5]) {
   323         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data[5] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   324         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data[5] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   325         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data[5] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   326         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data[5] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   327         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[5] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   328         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[5] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   329         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[5] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   330         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[5] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   331     }
   332 
   333     axis = ((int)*(Sint16*)(&data[6]) * 64) - 32768;
   334     if (axis == 32704) {
   335         axis = 32767;
   336     }
   337     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   338     axis = ((int)*(Sint16*)(&data[8]) * 64) - 32768;
   339     if (axis == 32704) {
   340         axis = 32767;
   341     }
   342     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   343     axis = *(Sint16*)(&data[10]);
   344     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   345     axis = *(Sint16*)(&data[12]);
   346     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~axis);
   347     axis = *(Sint16*)(&data[14]);
   348     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   349     axis = *(Sint16*)(&data[16]);
   350     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~axis);
   351 
   352     SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
   353 }
   354 
   355 static void
   356 HIDAPI_DriverXboxOne_HandleModePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
   357 {
   358     if (data[1] == 0x30) {
   359         /* The Xbox One S controller needs acks for mode reports */
   360         const Uint8 seqnum = data[2];
   361         const Uint8 ack[] = { 0x01, 0x20, seqnum, 0x09, 0x00, 0x07, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 };
   362         hid_write(dev, ack, sizeof(ack));
   363     }
   364 
   365     SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[4] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   366 }
   367 
   368 static SDL_bool
   369 HIDAPI_DriverXboxOne_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
   370 {
   371     SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
   372     Uint8 data[USB_PACKET_LENGTH];
   373     int size;
   374 
   375     if (!ctx->initialized) {
   376         if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->start_time + CONTROLLER_INIT_DELAY_MS)) {
   377             if (!SendControllerInit(dev, ctx)) {
   378                 return SDL_FALSE;
   379             }
   380             ctx->initialized = SDL_TRUE;
   381         }
   382     }
   383 
   384     while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
   385 #ifdef DEBUG_XBOX_PROTOCOL
   386         SDL_Log("Xbox One packet: size = %d\n"
   387                 "                 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n"
   388                 "                 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n"
   389                 "                 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n",
   390                     size,
   391                     data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
   392                     data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
   393                     data[16], data[17], data[18], data[19]);
   394 #endif
   395         switch (data[0]) {
   396         case 0x20:
   397             HIDAPI_DriverXboxOne_HandleStatePacket(joystick, dev, ctx, data, size);
   398             break;
   399         case 0x07:
   400             HIDAPI_DriverXboxOne_HandleModePacket(joystick, dev, ctx, data, size);
   401             break;
   402         default:
   403 #ifdef DEBUG_JOYSTICK
   404             SDL_Log("Unknown Xbox One packet: 0x%.2x\n", data[0]);
   405 #endif
   406             break;
   407         }
   408     }
   409 
   410     if (ctx->rumble_expiration) {
   411         Uint32 now = SDL_GetTicks();
   412         if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
   413             HIDAPI_DriverXboxOne_Rumble(joystick, dev, context, 0, 0, 0);
   414         }
   415     }
   416 
   417     return (size >= 0);
   418 }
   419 
   420 static void
   421 HIDAPI_DriverXboxOne_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
   422 {
   423     SDL_free(context);
   424 }
   425 
   426 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
   427 {
   428     SDL_HINT_JOYSTICK_HIDAPI_XBOX,
   429     SDL_TRUE,
   430     HIDAPI_DriverXboxOne_IsSupportedDevice,
   431     HIDAPI_DriverXboxOne_GetDeviceName,
   432     HIDAPI_DriverXboxOne_Init,
   433     HIDAPI_DriverXboxOne_Rumble,
   434     HIDAPI_DriverXboxOne_Update,
   435     HIDAPI_DriverXboxOne_Quit
   436 };
   437 
   438 #endif /* SDL_JOYSTICK_HIDAPI_XBOXONE */
   439 
   440 #endif /* SDL_JOYSTICK_HIDAPI */
   441 
   442 /* vi: set ts=4 sw=4 expandtab: */