src/joystick/hidapi/SDL_hidapi_ps4.c
author Sam Lantinga
Mon, 16 Dec 2019 10:20:03 -0800
changeset 13348 448528dc13da
parent 13277 b72b5a030eee
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 /* This driver supports both simplified reports and the extended input reports enabled by Steam.
    22    Code and logic contributed by Valve Corporation under the SDL zlib license.
    23 */
    24 #include "../../SDL_internal.h"
    25 
    26 #ifdef SDL_JOYSTICK_HIDAPI
    27 
    28 #include "SDL_hints.h"
    29 #include "SDL_log.h"
    30 #include "SDL_events.h"
    31 #include "SDL_timer.h"
    32 #include "SDL_joystick.h"
    33 #include "SDL_gamecontroller.h"
    34 #include "../SDL_sysjoystick.h"
    35 #include "SDL_hidapijoystick_c.h"
    36 
    37 
    38 #ifdef SDL_JOYSTICK_HIDAPI_PS4
    39 
    40 #define SONY_USB_VID        0x054C
    41 #define SONY_DS4_PID        0x05C4
    42 #define SONY_DS4_DONGLE_PID 0x0BA0
    43 #define SONY_DS4_SLIM_PID   0x09CC
    44 
    45 #define RAZER_USB_VID       0x1532
    46 #define RAZER_PANTHERA_PID  0X0401
    47 #define RAZER_PANTHERA_EVO_PID  0x1008
    48 
    49 #define USB_PACKET_LENGTH   64
    50 
    51 typedef enum
    52 {
    53     k_EPS4ReportIdUsbState = 1,
    54     k_EPS4ReportIdUsbEffects = 5,
    55     k_EPS4ReportIdBluetoothState = 17,
    56     k_EPS4ReportIdBluetoothEffects = 17,
    57     k_EPS4ReportIdDisconnectMessage = 226,
    58 } EPS4ReportId;
    59 
    60 typedef enum 
    61 {
    62     k_ePS4FeatureReportIdGyroCalibration_USB = 0x02,
    63     k_ePS4FeatureReportIdGyroCalibration_BT = 0x05,
    64     k_ePS4FeatureReportIdSerialNumber = 0x12,
    65 } EPS4FeatureReportID;
    66 
    67 typedef struct
    68 {
    69     Uint8 ucLeftJoystickX;
    70     Uint8 ucLeftJoystickY;
    71     Uint8 ucRightJoystickX;
    72     Uint8 ucRightJoystickY;
    73     Uint8 rgucButtonsHatAndCounter[ 3 ];
    74     Uint8 ucTriggerLeft;
    75     Uint8 ucTriggerRight;
    76     Uint8 _rgucPad0[ 3 ];
    77     Sint16 sGyroX;
    78     Sint16 sGyroY;
    79     Sint16 sGyroZ;
    80     Sint16 sAccelX;
    81     Sint16 sAccelY;
    82     Sint16 sAccelZ;
    83     Uint8 _rgucPad1[ 5 ];
    84     Uint8 ucBatteryLevel;
    85     Uint8 _rgucPad2[ 4 ];
    86     Uint8 ucTrackpadCounter1;
    87     Uint8 rgucTrackpadData1[ 3 ];
    88     Uint8 ucTrackpadCounter2;
    89     Uint8 rgucTrackpadData2[ 3 ];
    90 } PS4StatePacket_t;
    91 
    92 typedef struct
    93 {
    94     Uint8 ucRumbleRight;
    95     Uint8 ucRumbleLeft;
    96     Uint8 ucLedRed;
    97     Uint8 ucLedGreen;
    98     Uint8 ucLedBlue;
    99     Uint8 ucLedDelayOn;
   100     Uint8 ucLedDelayOff;
   101     Uint8 _rgucPad0[ 8 ];
   102     Uint8 ucVolumeLeft;
   103     Uint8 ucVolumeRight;
   104     Uint8 ucVolumeMic;
   105     Uint8 ucVolumeSpeaker;
   106 } DS4EffectsState_t;
   107 
   108 typedef struct {
   109     SDL_bool is_dongle;
   110     SDL_bool is_bluetooth;
   111     SDL_bool audio_supported;
   112     SDL_bool rumble_supported;
   113     Uint8 volume;
   114     Uint32 last_volume_check;
   115     Uint32 rumble_expiration;
   116     PS4StatePacket_t last_state;
   117 } SDL_DriverPS4_Context;
   118 
   119 
   120 /* Public domain CRC implementation adapted from:
   121    http://home.thep.lu.se/~bjorn/crc/crc32_simple.c
   122 */
   123 static Uint32 crc32_for_byte(Uint32 r)
   124 {
   125     int i;
   126     for(i = 0; i < 8; ++i) {
   127         r = (r & 1? 0: (Uint32)0xEDB88320L) ^ r >> 1;
   128     }
   129     return r ^ (Uint32)0xFF000000L;
   130 }
   131 
   132 static Uint32 crc32(Uint32 crc, const void *data, int count)
   133 {
   134     int i;
   135     for(i = 0; i < count; ++i) {
   136         crc = crc32_for_byte((Uint8)crc ^ ((const Uint8*)data)[i]) ^ crc >> 8;
   137     }
   138     return crc;
   139 }
   140 
   141 static SDL_bool
   142 HIDAPI_DriverPS4_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name)
   143 {
   144     return (SDL_GetJoystickGameControllerType(vendor_id, product_id, name) == SDL_CONTROLLER_TYPE_PS4);
   145 }
   146 
   147 static const char *
   148 HIDAPI_DriverPS4_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
   149 {
   150     if (vendor_id == SONY_USB_VID) {
   151         return "PS4 Controller";
   152     }
   153     return NULL;
   154 }
   155 
   156 static SDL_bool ReadFeatureReport(hid_device *dev, Uint8 report_id, Uint8 *data, size_t size)
   157 {
   158     Uint8 report[USB_PACKET_LENGTH + 1];
   159 
   160     SDL_memset(report, 0, sizeof(report));
   161     report[0] = report_id;
   162     if (hid_get_feature_report(dev, report, sizeof(report)) < 0) {
   163         return SDL_FALSE;
   164     }
   165     SDL_memcpy(data, report, SDL_min(size, sizeof(report)));
   166     return SDL_TRUE;
   167 }
   168 
   169 static SDL_bool CheckUSBConnected(hid_device *dev)
   170 {
   171     int i;
   172     Uint8 data[16];
   173 
   174     /* This will fail if we're on Bluetooth */
   175     if (ReadFeatureReport(dev, k_ePS4FeatureReportIdSerialNumber, data, sizeof(data))) {
   176         for (i = 0; i < sizeof(data); ++i) {
   177             if (data[i] != 0x00) {
   178                 return SDL_TRUE;
   179             }
   180         }
   181         /* Maybe the dongle without a connected controller? */
   182     }
   183     return SDL_FALSE;
   184 }
   185 
   186 static SDL_bool HIDAPI_DriverPS4_CanRumble(Uint16 vendor_id, Uint16 product_id)
   187 {
   188     /* The Razer Panthera fight stick hangs when trying to rumble */
   189     if (vendor_id == RAZER_USB_VID &&
   190         (product_id == RAZER_PANTHERA_PID || product_id == RAZER_PANTHERA_EVO_PID)) {
   191         return SDL_FALSE;
   192     }
   193     return SDL_TRUE;
   194 }
   195 
   196 static int HIDAPI_DriverPS4_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
   197 
   198 static SDL_bool
   199 HIDAPI_DriverPS4_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
   200 {
   201     SDL_DriverPS4_Context *ctx;
   202 
   203     ctx = (SDL_DriverPS4_Context *)SDL_calloc(1, sizeof(*ctx));
   204     if (!ctx) {
   205         SDL_OutOfMemory();
   206         return SDL_FALSE;
   207     }
   208     *context = ctx;
   209 
   210     /* Check for type of connection */
   211     ctx->is_dongle = (vendor_id == SONY_USB_VID && product_id == SONY_DS4_DONGLE_PID);
   212     if (ctx->is_dongle) {
   213         ctx->is_bluetooth = SDL_FALSE;
   214     } else if (vendor_id == SONY_USB_VID) {
   215         ctx->is_bluetooth = !CheckUSBConnected(dev);
   216     } else {
   217         /* Third party controllers appear to all be wired */
   218         ctx->is_bluetooth = SDL_FALSE;
   219     }
   220 #ifdef DEBUG_PS4
   221     SDL_Log("PS4 dongle = %s, bluetooth = %s\n", ctx->is_dongle ? "TRUE" : "FALSE", ctx->is_bluetooth ? "TRUE" : "FALSE");
   222 #endif
   223 
   224     /* Check to see if audio is supported */
   225     if (vendor_id == SONY_USB_VID &&
   226         (product_id == SONY_DS4_SLIM_PID || product_id == SONY_DS4_DONGLE_PID )) {
   227         ctx->audio_supported = SDL_TRUE;
   228     }
   229 
   230     if (HIDAPI_DriverPS4_CanRumble(vendor_id, product_id)) {
   231         if (ctx->is_bluetooth) {
   232             ctx->rumble_supported = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, SDL_FALSE);
   233         } else {
   234             ctx->rumble_supported = SDL_TRUE;
   235         }
   236     }
   237 
   238     /* Initialize LED and effect state */
   239     HIDAPI_DriverPS4_Rumble(joystick, dev, ctx, 0, 0, 0);
   240 
   241     /* Initialize the joystick capabilities */
   242     joystick->nbuttons = 16;
   243     joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
   244     joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
   245 
   246     return SDL_TRUE;
   247 }
   248 
   249 static int
   250 HIDAPI_DriverPS4_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   251 {
   252     SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context;
   253     DS4EffectsState_t *effects;
   254     Uint8 data[78];
   255     int report_size, offset;
   256 
   257     if (!ctx->rumble_supported) {
   258         return SDL_Unsupported();
   259     }
   260 
   261     /* In order to send rumble, we have to send a complete effect packet */
   262     SDL_memset(data, 0, sizeof(data));
   263 
   264     if (ctx->is_bluetooth) {
   265         data[0] = k_EPS4ReportIdBluetoothEffects;
   266         data[1] = 0xC0 | 0x04;  /* Magic value HID + CRC, also sets interval to 4ms for samples */
   267         data[3] = 0x03;  /* 0x1 is rumble, 0x2 is lightbar, 0x4 is the blink interval */
   268 
   269         report_size = 78;
   270         offset = 6;
   271     } else {
   272         data[0] = k_EPS4ReportIdUsbEffects;
   273         data[1] = 0x07;  /* Magic value */
   274 
   275         report_size = 32;
   276         offset = 4;
   277     }
   278     effects = (DS4EffectsState_t *)&data[offset];
   279 
   280     effects->ucRumbleLeft = (low_frequency_rumble >> 8);
   281     effects->ucRumbleRight = (high_frequency_rumble >> 8);
   282 
   283     effects->ucLedRed = 0;
   284     effects->ucLedGreen = 0;
   285     effects->ucLedBlue = 80;
   286 
   287     if (ctx->is_bluetooth) {
   288         /* Bluetooth reports need a CRC at the end of the packet (at least on Linux) */
   289         Uint8 ubHdr = 0xA2; /* hidp header is part of the CRC calculation */
   290         Uint32 unCRC;
   291         unCRC = crc32(0, &ubHdr, 1);
   292         unCRC = crc32(unCRC, data, (Uint32)(report_size - sizeof(unCRC)));
   293         SDL_memcpy(&data[report_size - sizeof(unCRC)], &unCRC, sizeof(unCRC));
   294     }
   295 
   296     if (hid_write(dev, data, report_size) != report_size) {
   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_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverPS4_Context *ctx, PS4StatePacket_t *packet)
   310 {
   311     Sint16 axis;
   312 
   313     if (ctx->last_state.rgucButtonsHatAndCounter[0] != packet->rgucButtonsHatAndCounter[0]) {
   314         {
   315             Uint8 data = (packet->rgucButtonsHatAndCounter[0] >> 4);
   316 
   317             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   318             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   319             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   320             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   321         }
   322         {
   323             Uint8 data = (packet->rgucButtonsHatAndCounter[0] & 0x0F);
   324             SDL_bool dpad_up = SDL_FALSE;
   325             SDL_bool dpad_down = SDL_FALSE;
   326             SDL_bool dpad_left = SDL_FALSE;
   327             SDL_bool dpad_right = SDL_FALSE;
   328 
   329             switch (data) {
   330             case 0:
   331                 dpad_up = SDL_TRUE;
   332                 break;
   333             case 1:
   334                 dpad_up = SDL_TRUE;
   335                 dpad_right = SDL_TRUE;
   336                 break;
   337             case 2:
   338                 dpad_right = SDL_TRUE;
   339                 break;
   340             case 3:
   341                 dpad_right = SDL_TRUE;
   342                 dpad_down = SDL_TRUE;
   343                 break;
   344             case 4:
   345                 dpad_down = SDL_TRUE;
   346                 break;
   347             case 5:
   348                 dpad_left = SDL_TRUE;
   349                 dpad_down = SDL_TRUE;
   350                 break;
   351             case 6:
   352                 dpad_left = SDL_TRUE;
   353                 break;
   354             case 7:
   355                 dpad_up = SDL_TRUE;
   356                 dpad_left = SDL_TRUE;
   357                 break;
   358             default:
   359                 break;
   360             }
   361             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
   362             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
   363             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
   364             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
   365         }
   366     }
   367 
   368     if (ctx->last_state.rgucButtonsHatAndCounter[1] != packet->rgucButtonsHatAndCounter[1]) {
   369         Uint8 data = packet->rgucButtonsHatAndCounter[1];
   370 
   371         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   372         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   373         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   374         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   375         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   376         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   377     }
   378 
   379     if (ctx->last_state.rgucButtonsHatAndCounter[2] != packet->rgucButtonsHatAndCounter[2]) {
   380         Uint8 data = (packet->rgucButtonsHatAndCounter[2] & 0x03);
   381 
   382         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   383         SDL_PrivateJoystickButton(joystick, 15, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   384     }
   385 
   386     axis = ((int)packet->ucTriggerLeft * 257) - 32768;
   387     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   388     axis = ((int)packet->ucTriggerRight * 257) - 32768;
   389     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   390     axis = ((int)packet->ucLeftJoystickX * 257) - 32768;
   391     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   392     axis = ((int)packet->ucLeftJoystickY * 257) - 32768;
   393     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
   394     axis = ((int)packet->ucRightJoystickX * 257) - 32768;
   395     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   396     axis = ((int)packet->ucRightJoystickY * 257) - 32768;
   397     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
   398 
   399     if (packet->ucBatteryLevel & 0x10) {
   400         joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
   401     } else {
   402         /* Battery level ranges from 0 to 10 */
   403         int level = (packet->ucBatteryLevel & 0xF);
   404         if (level == 0) {
   405             joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY;
   406         } else if (level <= 2) {
   407             joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW;
   408         } else if (level <= 7) {
   409             joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM;
   410         } else {
   411             joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
   412         }
   413     }
   414 
   415     SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state));
   416 }
   417 
   418 static SDL_bool
   419 HIDAPI_DriverPS4_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
   420 {
   421     SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context;
   422     Uint8 data[USB_PACKET_LENGTH];
   423     int size;
   424 
   425     while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
   426         switch (data[0]) {
   427         case k_EPS4ReportIdUsbState:
   428             HIDAPI_DriverPS4_HandleStatePacket(joystick, dev, ctx, (PS4StatePacket_t *)&data[1]);
   429             break;
   430         case k_EPS4ReportIdBluetoothState:
   431             /* Bluetooth state packets have two additional bytes at the beginning */
   432             HIDAPI_DriverPS4_HandleStatePacket(joystick, dev, ctx, (PS4StatePacket_t *)&data[3]);
   433             break;
   434         default:
   435 #ifdef DEBUG_JOYSTICK
   436             SDL_Log("Unknown PS4 packet: 0x%.2x\n", data[0]);
   437 #endif
   438             break;
   439         }
   440     }
   441 
   442     if (ctx->rumble_expiration) {
   443         Uint32 now = SDL_GetTicks();
   444         if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
   445             HIDAPI_DriverPS4_Rumble(joystick, dev, context, 0, 0, 0);
   446         }
   447     }
   448 
   449     return (size >= 0);
   450 }
   451 
   452 static void
   453 HIDAPI_DriverPS4_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
   454 {
   455     SDL_free(context);
   456 }
   457 
   458 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4 =
   459 {
   460     SDL_HINT_JOYSTICK_HIDAPI_PS4,
   461     SDL_TRUE,
   462     HIDAPI_DriverPS4_IsSupportedDevice,
   463     HIDAPI_DriverPS4_GetDeviceName,
   464     HIDAPI_DriverPS4_Init,
   465     HIDAPI_DriverPS4_Rumble,
   466     HIDAPI_DriverPS4_Update,
   467     HIDAPI_DriverPS4_Quit
   468 };
   469 
   470 #endif /* SDL_JOYSTICK_HIDAPI_PS4 */
   471 
   472 #endif /* SDL_JOYSTICK_HIDAPI */
   473 
   474 /* vi: set ts=4 sw=4 expandtab: */