sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_hidapi_ps5.c (35554B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 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_events.h"
     27 #include "SDL_timer.h"
     28 #include "SDL_joystick.h"
     29 #include "SDL_gamecontroller.h"
     30 #include "../SDL_sysjoystick.h"
     31 #include "SDL_hidapijoystick_c.h"
     32 #include "SDL_hidapi_rumble.h"
     33 
     34 
     35 #ifdef SDL_JOYSTICK_HIDAPI_PS5
     36 
     37 /* Define this if you want to log all packets from the controller */
     38 /*#define DEBUG_PS5_PROTOCOL*/
     39 
     40 /* Define this if you want to log calibration data */
     41 /*#define DEBUG_PS5_CALIBRATION*/
     42 
     43 #define GYRO_RES_PER_DEGREE 1024.0f
     44 #define ACCEL_RES_PER_G     8192.0f
     45 #define BLUETOOTH_DISCONNECT_TIMEOUT_MS 500
     46 
     47 #define LOAD16(A, B)  (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
     48 
     49 typedef enum
     50 {
     51     k_EPS5ReportIdState = 0x01,
     52     k_EPS5ReportIdUsbEffects = 0x02,
     53     k_EPS5ReportIdBluetoothEffects = 0x31,
     54     k_EPS5ReportIdBluetoothState = 0x31,
     55 } EPS5ReportId;
     56 
     57 typedef enum
     58 {
     59     k_EPS5FeatureReportIdCalibration = 0x05,
     60     k_EPS5FeatureReportIdSerialNumber = 0x09,
     61 } EPS5FeatureReportId;
     62 
     63 typedef struct
     64 {
     65     Uint8 ucLeftJoystickX;
     66     Uint8 ucLeftJoystickY;
     67     Uint8 ucRightJoystickX;
     68     Uint8 ucRightJoystickY;
     69     Uint8 rgucButtonsHatAndCounter[3];
     70     Uint8 ucTriggerLeft;
     71     Uint8 ucTriggerRight;
     72 } PS5SimpleStatePacket_t;
     73 
     74 typedef struct
     75 {
     76     Uint8 ucLeftJoystickX;              /* 0 */
     77     Uint8 ucLeftJoystickY;              /* 1 */
     78     Uint8 ucRightJoystickX;             /* 2 */
     79     Uint8 ucRightJoystickY;             /* 3 */
     80     Uint8 ucTriggerLeft;                /* 4 */
     81     Uint8 ucTriggerRight;               /* 5 */
     82     Uint8 ucCounter;                    /* 6 */
     83     Uint8 rgucButtonsAndHat[3];         /* 7 */
     84     Uint8 ucZero;                       /* 10 */
     85     Uint8 rgucPacketSequence[4];        /* 11 - 32 bit little endian */
     86     Uint8 rgucGyroX[2];                 /* 15 */
     87     Uint8 rgucGyroY[2];                 /* 17 */
     88     Uint8 rgucGyroZ[2];                 /* 19 */
     89     Uint8 rgucAccelX[2];                /* 21 */
     90     Uint8 rgucAccelY[2];                /* 23 */
     91     Uint8 rgucAccelZ[2];                /* 25 */
     92     Uint8 rgucTimer1[4];                /* 27 - 32 bit little endian */
     93     Uint8 ucBatteryTemp;                /* 31 */
     94     Uint8 ucTouchpadCounter1;           /* 32 - high bit clear + counter */
     95     Uint8 rgucTouchpadData1[3];         /* 33 - X/Y, 12 bits per axis */
     96     Uint8 ucTouchpadCounter2;           /* 36 - high bit clear + counter */
     97     Uint8 rgucTouchpadData2[3];         /* 37 - X/Y, 12 bits per axis */
     98     Uint8 rgucUnknown1[8];              /* 40 */
     99     Uint8 rgucTimer2[4];                /* 48 - 32 bit little endian */
    100     Uint8 ucBatteryLevel;               /* 52 */
    101     Uint8 ucConnectState;               /* 53 - 0x08 = USB, 0x01 = headphone */
    102 
    103     /* There's more unknown data at the end, and a 32-bit CRC on Bluetooth */
    104 } PS5StatePacket_t;
    105 
    106 typedef struct
    107 {
    108     Uint8 ucEnableBits1;                /* 0 */
    109     Uint8 ucEnableBits2;                /* 1 */
    110     Uint8 ucRumbleRight;                /* 2 */
    111     Uint8 ucRumbleLeft;                 /* 3 */
    112     Uint8 ucHeadphoneVolume;            /* 4 */
    113     Uint8 ucSpeakerVolume;              /* 5 */
    114     Uint8 ucMicrophoneVolume;           /* 6 */
    115     Uint8 ucAudioEnableBits;            /* 7 */
    116     Uint8 ucMicLightMode;               /* 8 */
    117     Uint8 ucAudioMuteBits;              /* 9 */
    118     Uint8 rgucRightTriggerEffect[11];   /* 10 */
    119     Uint8 rgucLeftTriggerEffect[11];    /* 21 */
    120     Uint8 rgucUnknown1[6];              /* 32 */
    121     Uint8 ucLedFlags;                   /* 38 */
    122     Uint8 rgucUnknown2[2];              /* 39 */
    123     Uint8 ucLedAnim;                    /* 41 */
    124     Uint8 ucLedBrightness;              /* 42 */
    125     Uint8 ucPadLights;                  /* 43 */
    126     Uint8 ucLedRed;                     /* 44 */
    127     Uint8 ucLedGreen;                   /* 45 */
    128     Uint8 ucLedBlue;                    /* 46 */
    129 } DS5EffectsState_t;
    130 
    131 typedef enum {
    132     k_EDS5EffectNone,
    133     k_EDS5EffectRumbleStart,
    134     k_EDS5EffectRumble,
    135     k_EDS5EffectLEDReset,
    136     k_EDS5EffectLED,
    137     k_EDS5EffectPadLights,
    138     k_EDS5EffectMicLight,
    139 } EDS5Effect;
    140 
    141 typedef enum {
    142     k_EDS5LEDResetStateNone,
    143     k_EDS5LEDResetStatePending,
    144     k_EDS5LEDResetStateComplete,
    145 } EDS5LEDResetState;
    146 
    147 typedef struct {
    148     Sint16 bias;
    149     float sensitivity;
    150 } IMUCalibrationData;
    151 
    152 typedef struct {
    153     SDL_bool is_bluetooth;
    154     SDL_bool report_sensors;
    155     SDL_bool hardware_calibration;
    156     IMUCalibrationData calibration[6];
    157     Uint32 last_packet;
    158     int player_index;
    159     Uint8 rumble_left;
    160     Uint8 rumble_right;
    161     SDL_bool color_set;
    162     Uint8 led_red;
    163     Uint8 led_green;
    164     Uint8 led_blue;
    165     EDS5LEDResetState led_reset_state;
    166     union
    167     {
    168         PS5SimpleStatePacket_t simple;
    169         PS5StatePacket_t state;
    170     } last_state;
    171 } SDL_DriverPS5_Context;
    172 
    173 
    174 static SDL_bool
    175 HIDAPI_DriverPS5_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
    176 {
    177     return (type == SDL_CONTROLLER_TYPE_PS5) ? SDL_TRUE : SDL_FALSE;
    178 }
    179 
    180 static const char *
    181 HIDAPI_DriverPS5_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
    182 {
    183     if (vendor_id == USB_VENDOR_SONY) {
    184         return "PS5 Controller";
    185     }
    186     return NULL;
    187 }
    188 
    189 static int ReadFeatureReport(hid_device *dev, Uint8 report_id, Uint8 *report, size_t length)
    190 {
    191     SDL_memset(report, 0, length);
    192     report[0] = report_id;
    193     return hid_get_feature_report(dev, report, length);
    194 }
    195 
    196 static void
    197 SetLedsForPlayerIndex(DS5EffectsState_t *effects, int player_index)
    198 {
    199     /* This list is the same as what hid-sony.c uses in the Linux kernel.
    200        The first 4 values correspond to what the PS4 assigns.
    201     */
    202     static const Uint8 colors[7][3] = {
    203         { 0x00, 0x00, 0x40 }, /* Blue */
    204         { 0x40, 0x00, 0x00 }, /* Red */
    205         { 0x00, 0x40, 0x00 }, /* Green */
    206         { 0x20, 0x00, 0x20 }, /* Pink */
    207         { 0x02, 0x01, 0x00 }, /* Orange */
    208         { 0x00, 0x01, 0x01 }, /* Teal */
    209         { 0x01, 0x01, 0x01 }  /* White */
    210     };
    211 
    212     if (player_index >= 0) {
    213         player_index %= SDL_arraysize(colors);
    214     } else {
    215         player_index = 0;
    216     }
    217 
    218     effects->ucLedRed = colors[player_index][0];
    219     effects->ucLedGreen = colors[player_index][1];
    220     effects->ucLedBlue = colors[player_index][2];
    221 }
    222 
    223 static SDL_bool
    224 HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
    225 {
    226     return HIDAPI_JoystickConnected(device, NULL);
    227 }
    228 
    229 static int
    230 HIDAPI_DriverPS5_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
    231 {
    232     return -1;
    233 }
    234 
    235 static void
    236 HIDAPI_DriverPS5_LoadCalibrationData(SDL_HIDAPI_Device *device)
    237 {
    238     SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
    239     int i, size;
    240     Uint8 data[USB_PACKET_LENGTH];
    241 
    242     size = ReadFeatureReport(device->dev, k_EPS5FeatureReportIdCalibration, data, sizeof(data));
    243     if (size < 35) {
    244 #ifdef DEBUG_PS5_CALIBRATION
    245         SDL_Log("Short read of calibration data: %d, ignoring calibration\n", size);
    246 #endif
    247         return;
    248     }
    249 
    250     {
    251         Sint16 sGyroPitchBias, sGyroYawBias, sGyroRollBias;
    252         Sint16 sGyroPitchPlus, sGyroPitchMinus;
    253         Sint16 sGyroYawPlus, sGyroYawMinus;
    254         Sint16 sGyroRollPlus, sGyroRollMinus;
    255         Sint16 sGyroSpeedPlus, sGyroSpeedMinus;
    256 
    257         Sint16 sAccXPlus, sAccXMinus;
    258         Sint16 sAccYPlus, sAccYMinus;
    259         Sint16 sAccZPlus, sAccZMinus;
    260 
    261         float flNumerator;
    262         Sint16 sRange2g;
    263 
    264 #ifdef DEBUG_PS5_CALIBRATION
    265         HIDAPI_DumpPacket("PS5 calibration packet: size = %d", data, size);
    266 #endif
    267 
    268         sGyroPitchBias = LOAD16(data[1], data[2]);
    269         sGyroYawBias = LOAD16(data[3], data[4]);
    270         sGyroRollBias = LOAD16(data[5], data[6]);
    271 
    272         sGyroPitchPlus = LOAD16(data[7], data[8]);
    273         sGyroPitchMinus = LOAD16(data[9], data[10]);
    274         sGyroYawPlus = LOAD16(data[11], data[12]);
    275         sGyroYawMinus = LOAD16(data[13], data[14]);
    276         sGyroRollPlus = LOAD16(data[15], data[16]);
    277         sGyroRollMinus = LOAD16(data[17], data[18]);
    278 
    279         sGyroSpeedPlus = LOAD16(data[19], data[20]);
    280         sGyroSpeedMinus = LOAD16(data[21], data[22]);
    281 
    282         sAccXPlus = LOAD16(data[23], data[24]);
    283         sAccXMinus = LOAD16(data[25], data[26]);
    284         sAccYPlus = LOAD16(data[27], data[28]);
    285         sAccYMinus = LOAD16(data[29], data[30]);
    286         sAccZPlus = LOAD16(data[31], data[32]);
    287         sAccZMinus = LOAD16(data[33], data[34]);
    288 
    289         flNumerator = (sGyroSpeedPlus + sGyroSpeedMinus) * GYRO_RES_PER_DEGREE;
    290         ctx->calibration[0].bias = sGyroPitchBias;
    291         ctx->calibration[0].sensitivity = flNumerator / (sGyroPitchPlus - sGyroPitchMinus);
    292 
    293         ctx->calibration[1].bias = sGyroYawBias;
    294         ctx->calibration[1].sensitivity = flNumerator / (sGyroYawPlus - sGyroYawMinus);
    295 
    296         ctx->calibration[2].bias = sGyroRollBias;
    297         ctx->calibration[2].sensitivity = flNumerator / (sGyroRollPlus - sGyroRollMinus);
    298 
    299         sRange2g = sAccXPlus - sAccXMinus;
    300         ctx->calibration[3].bias = sAccXPlus - sRange2g / 2;
    301         ctx->calibration[3].sensitivity = 2.0f * ACCEL_RES_PER_G / (float)sRange2g;
    302 
    303         sRange2g = sAccYPlus - sAccYMinus;
    304         ctx->calibration[4].bias = sAccYPlus - sRange2g / 2;
    305         ctx->calibration[4].sensitivity = 2.0f * ACCEL_RES_PER_G / (float)sRange2g;
    306 
    307         sRange2g = sAccZPlus - sAccZMinus;
    308         ctx->calibration[5].bias = sAccZPlus - sRange2g / 2;
    309         ctx->calibration[5].sensitivity = 2.0f * ACCEL_RES_PER_G / (float)sRange2g;
    310 
    311         ctx->hardware_calibration = SDL_TRUE;
    312         for (i = 0; i < 6; ++i) {
    313             float divisor = (i < 3 ? 64.0f : 1.0f);
    314 #ifdef DEBUG_PS5_CALIBRATION
    315             SDL_Log("calibration[%d] bias = %d, sensitivity = %f\n", i, ctx->calibration[i].bias, ctx->calibration[i].sensitivity);
    316 #endif
    317             /* Some controllers have a bad calibration */
    318             if ((SDL_abs(ctx->calibration[i].bias) > 1024) || (SDL_fabs(1.0f - ctx->calibration[i].sensitivity / divisor) > 0.5f)) {
    319 #ifdef DEBUG_PS5_CALIBRATION
    320                 SDL_Log("invalid calibration, ignoring\n");
    321 #endif
    322                 ctx->hardware_calibration = SDL_FALSE;
    323             }
    324         }
    325     }
    326 }
    327 
    328 static float
    329 HIDAPI_DriverPS5_ApplyCalibrationData(SDL_DriverPS5_Context *ctx, int index, Sint16 value)
    330 {
    331     float result;
    332 
    333     if (ctx->hardware_calibration) {
    334         IMUCalibrationData *calibration = &ctx->calibration[index];
    335 
    336         result = (value - calibration->bias) * calibration->sensitivity;
    337     } else if (index < 3) {
    338         result = value * 64.f;
    339     } else {
    340         result = value;
    341     }
    342 
    343     /* Convert the raw data to the units expected by SDL */
    344     if (index < 3) {
    345         result = (result / GYRO_RES_PER_DEGREE) * (float)M_PI / 180.0f;
    346     } else {
    347         result = (result / ACCEL_RES_PER_G) * SDL_STANDARD_GRAVITY;
    348     }
    349     return result;
    350 }
    351 
    352 static int
    353 HIDAPI_DriverPS5_UpdateEffects(SDL_HIDAPI_Device *device, EDS5Effect effect)
    354 {
    355     SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
    356     DS5EffectsState_t *effects;
    357     Uint8 data[78];
    358     int report_size, offset;
    359     Uint8 *pending_data;
    360     int *pending_size;
    361     int maximum_size;
    362 
    363 
    364     SDL_zero(data);
    365 
    366     if (ctx->is_bluetooth) {
    367         data[0] = k_EPS5ReportIdBluetoothEffects;
    368         data[1] = 0x02;  /* Magic value */
    369 
    370         report_size = 78;
    371         offset = 2;
    372     } else {
    373         data[0] = k_EPS5ReportIdUsbEffects;
    374 
    375         report_size = 48;
    376         offset = 1;
    377     }
    378     effects = (DS5EffectsState_t *)&data[offset];
    379 
    380     /* Make sure the Bluetooth connection sequence has completed before sending LED color change */
    381     if (effect == k_EDS5EffectLED && ctx->is_bluetooth) {
    382         if (ctx->led_reset_state != k_EDS5LEDResetStateComplete) {
    383             ctx->led_reset_state = k_EDS5LEDResetStatePending;
    384             return 0;
    385         }
    386     }
    387 
    388     if (ctx->rumble_left || ctx->rumble_right) {
    389         effects->ucEnableBits1 |= 0x01; /* Enable rumble emulation */
    390         effects->ucEnableBits1 |= 0x02; /* Disable audio haptics */
    391 
    392         /* Shift to reduce effective rumble strength to match Xbox controllers */
    393         effects->ucRumbleLeft = ctx->rumble_left >> 1;
    394         effects->ucRumbleRight = ctx->rumble_right >> 1;
    395     } else {
    396         /* Leaving emulated rumble bits off will restore audio haptics */
    397     }
    398 
    399     switch (effect) {
    400     case k_EDS5EffectRumbleStart:
    401         effects->ucEnableBits1 |= 0x02; /* Disable audio haptics */
    402         break;
    403     case k_EDS5EffectRumble:
    404         /* Already handled above */
    405         break;
    406     case k_EDS5EffectLEDReset:
    407         effects->ucEnableBits2 |= 0x08; /* Reset LED state */
    408         break;
    409     case k_EDS5EffectLED:
    410         effects->ucEnableBits2 |= 0x04; /* Enable LED color */
    411 
    412         /* Populate the LED state with the appropriate color from our lookup table */
    413         if (ctx->color_set) {
    414             effects->ucLedRed = ctx->led_red;
    415             effects->ucLedGreen = ctx->led_green;
    416             effects->ucLedBlue = ctx->led_blue;
    417         } else {
    418             SetLedsForPlayerIndex(effects, ctx->player_index);
    419         }
    420         break;
    421     case k_EDS5EffectPadLights:
    422         effects->ucEnableBits2 |= 0x10; /* Enable touchpad lights */
    423 
    424         effects->ucPadLights = 0x00;    /* Bitmask, 0x1F enables all lights, 0x20 changes instantly instead of fade */
    425         break;
    426     case k_EDS5EffectMicLight:
    427         effects->ucEnableBits2 |= 0x01; /* Enable microphone light */
    428 
    429         effects->ucMicLightMode = 0;    /* Bitmask, 0x00 = off, 0x01 = solid, 0x02 = pulse */
    430         break;
    431     default:
    432         break;
    433     }
    434 
    435     if (ctx->is_bluetooth) {
    436         /* Bluetooth reports need a CRC at the end of the packet (at least on Linux) */
    437         Uint8 ubHdr = 0xA2; /* hidp header is part of the CRC calculation */
    438         Uint32 unCRC;
    439         unCRC = SDL_crc32(0, &ubHdr, 1);
    440         unCRC = SDL_crc32(unCRC, data, (size_t)(report_size - sizeof(unCRC)));
    441         SDL_memcpy(&data[report_size - sizeof(unCRC)], &unCRC, sizeof(unCRC));
    442     }
    443 
    444     if (SDL_HIDAPI_LockRumble() < 0) {
    445         return -1;
    446     }
    447 
    448     /* See if we can update an existing pending request */
    449     if (SDL_HIDAPI_GetPendingRumbleLocked(device, &pending_data, &pending_size, &maximum_size)) {
    450         DS5EffectsState_t *pending_effects = (DS5EffectsState_t *)&pending_data[offset];
    451         if (report_size == *pending_size &&
    452             effects->ucEnableBits1 == pending_effects->ucEnableBits1 &&
    453             effects->ucEnableBits2 == pending_effects->ucEnableBits2) {
    454             /* We're simply updating the data for this request */
    455             SDL_memcpy(pending_data, data, report_size);
    456             SDL_HIDAPI_UnlockRumble();
    457             return 0;
    458         }
    459     }
    460 
    461     return SDL_HIDAPI_SendRumbleAndUnlock(device, data, report_size);
    462 }
    463 
    464 static void
    465 HIDAPI_DriverPS5_SetBluetooth(SDL_HIDAPI_Device *device, SDL_bool is_bluetooth)
    466 {
    467     SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
    468 
    469     if (ctx->is_bluetooth != is_bluetooth) {
    470         ctx->is_bluetooth = is_bluetooth;
    471         HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectLED);
    472     }
    473 }
    474 
    475 static void
    476 HIDAPI_DriverPS5_CheckPendingLEDReset(SDL_HIDAPI_Device *device)
    477 {
    478     SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
    479     const PS5StatePacket_t *packet = &ctx->last_state.state;
    480 
    481     /* Check the timer to make sure the Bluetooth connection LED animation is complete */
    482     const Uint32 connection_complete = 10000000;
    483     Uint32 timer = ((Uint32)packet->rgucTimer1[0] <<  0) |
    484                    ((Uint32)packet->rgucTimer1[1] <<  8) |
    485                    ((Uint32)packet->rgucTimer1[2] << 16) |
    486                    ((Uint32)packet->rgucTimer1[3] << 24);
    487     if (timer >= connection_complete) {
    488         HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectLEDReset);
    489 
    490         ctx->led_reset_state = k_EDS5LEDResetStateComplete;
    491 
    492         HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectLED);
    493     }
    494 }
    495 
    496 static void
    497 HIDAPI_DriverPS5_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
    498 {
    499     SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
    500 
    501     if (!ctx) {
    502         return;
    503     }
    504 
    505     ctx->player_index = player_index;
    506 
    507     /* This will set the new LED state based on the new player index */
    508     HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectLED);
    509 }
    510 
    511 static SDL_bool
    512 HIDAPI_DriverPS5_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
    513 {
    514     SDL_DriverPS5_Context *ctx;
    515     Uint8 data[USB_PACKET_LENGTH];
    516 
    517     ctx = (SDL_DriverPS5_Context *)SDL_calloc(1, sizeof(*ctx));
    518     if (!ctx) {
    519         SDL_OutOfMemory();
    520         return SDL_FALSE;
    521     }
    522     ctx->last_packet = SDL_GetTicks();
    523 
    524     device->dev = hid_open_path(device->path, 0);
    525     if (!device->dev) {
    526         SDL_free(ctx);
    527         SDL_SetError("Couldn't open %s", device->path);
    528         return SDL_FALSE;
    529     }
    530     device->context = ctx;
    531 
    532     /* Read the serial number (Bluetooth address in reverse byte order)
    533        This will also enable enhanced reports over Bluetooth
    534     */
    535     if (ReadFeatureReport(device->dev, k_EPS5FeatureReportIdSerialNumber, data, sizeof(data)) >= 7) {
    536         char serial[18];
    537 
    538         SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
    539             data[6], data[5], data[4], data[3], data[2], data[1]);
    540         joystick->serial = SDL_strdup(serial);
    541     }
    542 
    543     /* Initialize player index (needed for setting LEDs) */
    544     ctx->player_index = SDL_JoystickGetPlayerIndex(joystick);
    545 
    546     /* Initialize LED and effect state */
    547     HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectLED);
    548 
    549     /* Initialize the joystick capabilities */
    550     joystick->nbuttons = 17;
    551     joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
    552 
    553     SDL_PrivateJoystickAddTouchpad(joystick, 2);
    554     SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO);
    555     SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL);
    556 
    557     return SDL_TRUE;
    558 }
    559 
    560 static int
    561 HIDAPI_DriverPS5_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
    562 {
    563     SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
    564 
    565     if (!ctx->rumble_left && !ctx->rumble_right) {
    566         HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectRumbleStart);
    567     }
    568 
    569     ctx->rumble_left = (low_frequency_rumble >> 8);
    570     ctx->rumble_right = (high_frequency_rumble >> 8);
    571 
    572     return HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectRumble);
    573 }
    574 
    575 static int
    576 HIDAPI_DriverPS5_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
    577 {
    578     return SDL_Unsupported();
    579 }
    580 
    581 static SDL_bool
    582 HIDAPI_DriverPS5_HasJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
    583 {
    584     return SDL_FALSE;
    585 }
    586 
    587 static int
    588 HIDAPI_DriverPS5_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
    589 {
    590     SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
    591 
    592     ctx->color_set = SDL_TRUE;
    593     ctx->led_red = red;
    594     ctx->led_green = green;
    595     ctx->led_blue = blue;
    596 
    597     return HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectLED);
    598 }
    599 
    600 static int
    601 HIDAPI_DriverPS5_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
    602 {
    603     SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
    604 
    605     if (enabled) {
    606         HIDAPI_DriverPS5_LoadCalibrationData(device);
    607     }
    608     ctx->report_sensors = enabled;
    609 
    610     return 0;
    611 }
    612 
    613 static void
    614 HIDAPI_DriverPS5_HandleSimpleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverPS5_Context *ctx, PS5SimpleStatePacket_t *packet)
    615 {
    616     Sint16 axis;
    617 
    618     if (ctx->last_state.simple.rgucButtonsHatAndCounter[0] != packet->rgucButtonsHatAndCounter[0]) {
    619         {
    620             Uint8 data = (packet->rgucButtonsHatAndCounter[0] >> 4);
    621 
    622             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
    623             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
    624             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
    625             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
    626         }
    627         {
    628             Uint8 data = (packet->rgucButtonsHatAndCounter[0] & 0x0F);
    629             SDL_bool dpad_up = SDL_FALSE;
    630             SDL_bool dpad_down = SDL_FALSE;
    631             SDL_bool dpad_left = SDL_FALSE;
    632             SDL_bool dpad_right = SDL_FALSE;
    633 
    634             switch (data) {
    635             case 0:
    636                 dpad_up = SDL_TRUE;
    637                 break;
    638             case 1:
    639                 dpad_up = SDL_TRUE;
    640                 dpad_right = SDL_TRUE;
    641                 break;
    642             case 2:
    643                 dpad_right = SDL_TRUE;
    644                 break;
    645             case 3:
    646                 dpad_right = SDL_TRUE;
    647                 dpad_down = SDL_TRUE;
    648                 break;
    649             case 4:
    650                 dpad_down = SDL_TRUE;
    651                 break;
    652             case 5:
    653                 dpad_left = SDL_TRUE;
    654                 dpad_down = SDL_TRUE;
    655                 break;
    656             case 6:
    657                 dpad_left = SDL_TRUE;
    658                 break;
    659             case 7:
    660                 dpad_up = SDL_TRUE;
    661                 dpad_left = SDL_TRUE;
    662                 break;
    663             default:
    664                 break;
    665             }
    666             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
    667             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
    668             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
    669             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
    670         }
    671     }
    672 
    673     if (ctx->last_state.simple.rgucButtonsHatAndCounter[1] != packet->rgucButtonsHatAndCounter[1]) {
    674         Uint8 data = packet->rgucButtonsHatAndCounter[1];
    675 
    676         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
    677         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
    678         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
    679         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
    680         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED);
    681         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x80) ? SDL_PRESSED : SDL_RELEASED);
    682     }
    683 
    684     if (ctx->last_state.simple.rgucButtonsHatAndCounter[2] != packet->rgucButtonsHatAndCounter[2]) {
    685         Uint8 data = (packet->rgucButtonsHatAndCounter[2] & 0x03);
    686 
    687         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
    688         SDL_PrivateJoystickButton(joystick, 15, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
    689     }
    690 
    691     axis = ((int)packet->ucTriggerLeft * 257) - 32768;
    692     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
    693     axis = ((int)packet->ucTriggerRight * 257) - 32768;
    694     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
    695     axis = ((int)packet->ucLeftJoystickX * 257) - 32768;
    696     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
    697     axis = ((int)packet->ucLeftJoystickY * 257) - 32768;
    698     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
    699     axis = ((int)packet->ucRightJoystickX * 257) - 32768;
    700     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
    701     axis = ((int)packet->ucRightJoystickY * 257) - 32768;
    702     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
    703 
    704     SDL_memcpy(&ctx->last_state.simple, packet, sizeof(ctx->last_state.simple));
    705 }
    706 
    707 static void
    708 HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacket_t *packet)
    709 {
    710     static const float TOUCHPAD_SCALEX = 1.0f / 1920;
    711     static const float TOUCHPAD_SCALEY = 1.0f / 1070;
    712     Sint16 axis;
    713     Uint8 touchpad_state;
    714     int touchpad_x, touchpad_y;
    715 
    716     if (ctx->last_state.state.rgucButtonsAndHat[0] != packet->rgucButtonsAndHat[0]) {
    717         {
    718             Uint8 data = (packet->rgucButtonsAndHat[0] >> 4);
    719 
    720             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
    721             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
    722             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
    723             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
    724         }
    725         {
    726             Uint8 data = (packet->rgucButtonsAndHat[0] & 0x0F);
    727             SDL_bool dpad_up = SDL_FALSE;
    728             SDL_bool dpad_down = SDL_FALSE;
    729             SDL_bool dpad_left = SDL_FALSE;
    730             SDL_bool dpad_right = SDL_FALSE;
    731 
    732             switch (data) {
    733             case 0:
    734                 dpad_up = SDL_TRUE;
    735                 break;
    736             case 1:
    737                 dpad_up = SDL_TRUE;
    738                 dpad_right = SDL_TRUE;
    739                 break;
    740             case 2:
    741                 dpad_right = SDL_TRUE;
    742                 break;
    743             case 3:
    744                 dpad_right = SDL_TRUE;
    745                 dpad_down = SDL_TRUE;
    746                 break;
    747             case 4:
    748                 dpad_down = SDL_TRUE;
    749                 break;
    750             case 5:
    751                 dpad_left = SDL_TRUE;
    752                 dpad_down = SDL_TRUE;
    753                 break;
    754             case 6:
    755                 dpad_left = SDL_TRUE;
    756                 break;
    757             case 7:
    758                 dpad_up = SDL_TRUE;
    759                 dpad_left = SDL_TRUE;
    760                 break;
    761             default:
    762                 break;
    763             }
    764             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
    765             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
    766             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
    767             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
    768         }
    769     }
    770 
    771     if (ctx->last_state.state.rgucButtonsAndHat[1] != packet->rgucButtonsAndHat[1]) {
    772         Uint8 data = packet->rgucButtonsAndHat[1];
    773 
    774         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
    775         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
    776         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
    777         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
    778         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED);
    779         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x80) ? SDL_PRESSED : SDL_RELEASED);
    780     }
    781 
    782     if (ctx->last_state.state.rgucButtonsAndHat[2] != packet->rgucButtonsAndHat[2]) {
    783         Uint8 data = packet->rgucButtonsAndHat[2];
    784 
    785         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
    786         SDL_PrivateJoystickButton(joystick, 15, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
    787         SDL_PrivateJoystickButton(joystick, 16, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
    788     }
    789 
    790     axis = ((int)packet->ucTriggerLeft * 257) - 32768;
    791     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
    792     axis = ((int)packet->ucTriggerRight * 257) - 32768;
    793     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
    794     axis = ((int)packet->ucLeftJoystickX * 257) - 32768;
    795     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
    796     axis = ((int)packet->ucLeftJoystickY * 257) - 32768;
    797     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
    798     axis = ((int)packet->ucRightJoystickX * 257) - 32768;
    799     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
    800     axis = ((int)packet->ucRightJoystickY * 257) - 32768;
    801     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
    802 
    803     if (packet->ucBatteryLevel & 0x10) {
    804         /* 0x20 set means fully charged */
    805         SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_WIRED);
    806     } else {
    807         /* Battery level ranges from 0 to 10 */
    808         int level = (packet->ucBatteryLevel & 0xF);
    809         if (level == 0) {
    810             SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_EMPTY);
    811         } else if (level <= 2) {
    812             SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_LOW);
    813         } else if (level <= 7) {
    814             SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_MEDIUM);
    815         } else {
    816             SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_FULL);
    817         }
    818     }
    819 
    820     touchpad_state = ((packet->ucTouchpadCounter1 & 0x80) == 0) ? SDL_PRESSED : SDL_RELEASED;
    821     touchpad_x = packet->rgucTouchpadData1[0] | (((int)packet->rgucTouchpadData1[1] & 0x0F) << 8);
    822     touchpad_y = (packet->rgucTouchpadData1[1] >> 4) | ((int)packet->rgucTouchpadData1[2] << 4);
    823     SDL_PrivateJoystickTouchpad(joystick, 0, 0, touchpad_state, touchpad_x * TOUCHPAD_SCALEX, touchpad_y * TOUCHPAD_SCALEY, touchpad_state ? 1.0f : 0.0f);
    824 
    825     touchpad_state = ((packet->ucTouchpadCounter2 & 0x80) == 0) ? SDL_PRESSED : SDL_RELEASED;
    826     touchpad_x = packet->rgucTouchpadData2[0] | (((int)packet->rgucTouchpadData2[1] & 0x0F) << 8);
    827     touchpad_y = (packet->rgucTouchpadData2[1] >> 4) | ((int)packet->rgucTouchpadData2[2] << 4);
    828     SDL_PrivateJoystickTouchpad(joystick, 0, 1, touchpad_state, touchpad_x * TOUCHPAD_SCALEX, touchpad_y * TOUCHPAD_SCALEY, touchpad_state ? 1.0f : 0.0f);
    829 
    830     if (ctx->report_sensors) {
    831         float data[3];
    832 
    833         data[0] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 0, LOAD16(packet->rgucGyroX[0], packet->rgucGyroX[1]));
    834         data[1] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 1, LOAD16(packet->rgucGyroY[0], packet->rgucGyroY[1]));
    835         data[2] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 2, LOAD16(packet->rgucGyroZ[0], packet->rgucGyroZ[1]));
    836         SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_GYRO, data, 3);
    837 
    838         data[0] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 3, LOAD16(packet->rgucAccelX[0], packet->rgucAccelX[1]));
    839         data[1] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 4, LOAD16(packet->rgucAccelY[0], packet->rgucAccelY[1]));
    840         data[2] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 5, LOAD16(packet->rgucAccelZ[0], packet->rgucAccelZ[1]));
    841         SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_ACCEL, data, 3);
    842     }
    843 
    844     SDL_memcpy(&ctx->last_state.state, packet, sizeof(ctx->last_state.state));
    845 }
    846 
    847 static SDL_bool
    848 HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
    849 {
    850     SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
    851     SDL_Joystick *joystick = NULL;
    852     Uint8 data[USB_PACKET_LENGTH*2];
    853     int size;
    854     int packet_count = 0;
    855 
    856     if (device->num_joysticks > 0) {
    857         joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
    858     }
    859     if (!joystick) {
    860         return SDL_FALSE;
    861     }
    862 
    863     while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
    864 #ifdef DEBUG_PS5_PROTOCOL
    865         HIDAPI_DumpPacket("PS5 packet: size = %d", data, size);
    866 #endif
    867         ++packet_count;
    868         ctx->last_packet = SDL_GetTicks();
    869 
    870         switch (data[0]) {
    871         case k_EPS5ReportIdState:
    872             if (size == 10) {
    873                 HIDAPI_DriverPS5_SetBluetooth(device, SDL_TRUE);    /* Simple state packet over Bluetooth */
    874                 HIDAPI_DriverPS5_HandleSimpleStatePacket(joystick, device->dev, ctx, (PS5SimpleStatePacket_t *)&data[1]);
    875             } else {
    876                 HIDAPI_DriverPS5_SetBluetooth(device, SDL_FALSE);
    877                 HIDAPI_DriverPS5_HandleStatePacket(joystick, device->dev, ctx, (PS5StatePacket_t *)&data[1]);
    878             }
    879             break;
    880         case k_EPS5ReportIdBluetoothState:
    881             HIDAPI_DriverPS5_SetBluetooth(device, SDL_TRUE);
    882             HIDAPI_DriverPS5_HandleStatePacket(joystick, device->dev, ctx, (PS5StatePacket_t *)&data[2]);
    883             if (ctx->led_reset_state == k_EDS5LEDResetStatePending) {
    884                 HIDAPI_DriverPS5_CheckPendingLEDReset(device);
    885             }
    886             break;
    887         default:
    888 #ifdef DEBUG_JOYSTICK
    889             SDL_Log("Unknown PS5 packet: 0x%.2x\n", data[0]);
    890 #endif
    891             break;
    892         }
    893     }
    894 
    895     if (ctx->is_bluetooth && packet_count == 0) {
    896         /* Check to see if it looks like the device disconnected */
    897         if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->last_packet + BLUETOOTH_DISCONNECT_TIMEOUT_MS)) {
    898             /* Send an empty output report to tickle the Bluetooth stack */
    899             HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectNone);
    900         }
    901     }
    902 
    903     if (size < 0) {
    904         /* Read error, device is disconnected */
    905         HIDAPI_JoystickDisconnected(device, joystick->instance_id);
    906     }
    907     return (size >= 0);
    908 }
    909 
    910 static void
    911 HIDAPI_DriverPS5_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
    912 {
    913     hid_close(device->dev);
    914     device->dev = NULL;
    915 
    916     SDL_free(device->context);
    917     device->context = NULL;
    918 }
    919 
    920 static void
    921 HIDAPI_DriverPS5_FreeDevice(SDL_HIDAPI_Device *device)
    922 {
    923 }
    924 
    925 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS5 =
    926 {
    927     SDL_HINT_JOYSTICK_HIDAPI_PS5,
    928     SDL_TRUE,
    929     HIDAPI_DriverPS5_IsSupportedDevice,
    930     HIDAPI_DriverPS5_GetDeviceName,
    931     HIDAPI_DriverPS5_InitDevice,
    932     HIDAPI_DriverPS5_GetDevicePlayerIndex,
    933     HIDAPI_DriverPS5_SetDevicePlayerIndex,
    934     HIDAPI_DriverPS5_UpdateDevice,
    935     HIDAPI_DriverPS5_OpenJoystick,
    936     HIDAPI_DriverPS5_RumbleJoystick,
    937     HIDAPI_DriverPS5_RumbleJoystickTriggers,
    938     HIDAPI_DriverPS5_HasJoystickLED,
    939     HIDAPI_DriverPS5_SetJoystickLED,
    940     HIDAPI_DriverPS5_SetJoystickSensorsEnabled,
    941     HIDAPI_DriverPS5_CloseJoystick,
    942     HIDAPI_DriverPS5_FreeDevice,
    943 };
    944 
    945 #endif /* SDL_JOYSTICK_HIDAPI_PS5 */
    946 
    947 #endif /* SDL_JOYSTICK_HIDAPI */
    948 
    949 /* vi: set ts=4 sw=4 expandtab: */