Fixed the PS5 controller not disconnecting when powered off
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c
index 84232f9..fc05541 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps5.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps5.c
@@ -24,6 +24,7 @@
#include "SDL_hints.h"
#include "SDL_events.h"
+#include "SDL_timer.h"
#include "SDL_joystick.h"
#include "SDL_gamecontroller.h"
#include "../SDL_sysjoystick.h"
@@ -41,6 +42,7 @@
#define GYRO_RES_PER_DEGREE 1024.0f
#define ACCEL_RES_PER_G 8192.0f
+#define BLUETOOTH_DISCONNECT_TIMEOUT_MS 500
#define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
@@ -152,6 +154,7 @@ typedef struct {
SDL_bool report_sensors;
SDL_bool hardware_calibration;
IMUCalibrationData calibration[6];
+ Uint32 last_packet;
int player_index;
Uint8 rumble_left;
Uint8 rumble_right;
@@ -516,6 +519,7 @@ HIDAPI_DriverPS5_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
SDL_OutOfMemory();
return SDL_FALSE;
}
+ ctx->last_packet = SDL_GetTicks();
device->dev = hid_open_path(device->path, 0);
if (!device->dev) {
@@ -847,6 +851,7 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
SDL_Joystick *joystick = NULL;
Uint8 data[USB_PACKET_LENGTH*2];
int size;
+ int packet_count = 0;
if (device->num_joysticks > 0) {
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
@@ -859,6 +864,9 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
#ifdef DEBUG_PS5_PROTOCOL
HIDAPI_DumpPacket("PS5 packet: size = %d", data, size);
#endif
+ ++packet_count;
+ ctx->last_packet = SDL_GetTicks();
+
switch (data[0]) {
case k_EPS5ReportIdState:
if (size == 10) {
@@ -884,6 +892,14 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
}
}
+ if (ctx->is_bluetooth && packet_count == 0) {
+ /* Check to see if it looks like the device disconnected */
+ if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->last_packet + BLUETOOTH_DISCONNECT_TIMEOUT_MS)) {
+ /* Send an empty output report to tickle the Bluetooth stack */
+ HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectNone);
+ }
+ }
+
if (size < 0) {
/* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c
index c8683fe..a6a1c3d 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick.c
+++ b/src/joystick/hidapi/SDL_hidapijoystick.c
@@ -822,6 +822,11 @@ static void
HIDAPI_DelDevice(SDL_HIDAPI_Device *device)
{
SDL_HIDAPI_Device *curr, *last;
+
+#ifdef DEBUG_HIDAPI
+ SDL_Log("Removing HIDAPI device '%s' VID 0x%.4x, PID 0x%.4x, version %d, serial %s, interface %d, interface_class %d, interface_subclass %d, interface_protocol %d, usage page 0x%.4x, usage 0x%.4x, path = %s, driver = %s (%s)\n", device->name, device->vendor_id, device->product_id, device->version, device->serial ? device->serial : "NONE", device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol, device->usage_page, device->usage, device->path, device->driver ? device->driver->hint : "NONE", device->driver && device->driver->enabled ? "ENABLED" : "DISABLED");
+#endif
+
for (curr = SDL_HIDAPI_devices, last = NULL; curr; last = curr, curr = curr->next) {
if (curr == device) {
if (last) {
@@ -1002,7 +1007,9 @@ HIDAPI_UpdateDevices(void)
while (device) {
if (device->driver) {
if (SDL_TryLockMutex(device->dev_lock) == 0) {
+ device->updating = SDL_TRUE;
device->driver->UpdateDevice(device);
+ device->updating = SDL_FALSE;
SDL_UnlockMutex(device->dev_lock);
}
}
@@ -1200,11 +1207,19 @@ HIDAPI_JoystickClose(SDL_Joystick * joystick)
int i;
/* Wait up to 30 ms for pending rumble to complete */
+ if (device->updating) {
+ /* Unlock the device so rumble can complete */
+ SDL_UnlockMutex(device->dev_lock);
+ }
for (i = 0; i < 3; ++i) {
- while (SDL_AtomicGet(&device->rumble_pending) > 0) {
+ if (SDL_AtomicGet(&device->rumble_pending) > 0) {
SDL_Delay(10);
}
}
+ if (device->updating) {
+ /* Relock the device */
+ SDL_LockMutex(device->dev_lock);
+ }
device->driver->CloseJoystick(device, joystick);
diff --git a/src/joystick/hidapi/SDL_hidapijoystick_c.h b/src/joystick/hidapi/SDL_hidapijoystick_c.h
index d16a673..5af5b08 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick_c.h
+++ b/src/joystick/hidapi/SDL_hidapijoystick_c.h
@@ -76,6 +76,9 @@ typedef struct _SDL_HIDAPI_Device
/* Used during scanning for device changes */
SDL_bool seen;
+ /* Used to flag that the device is being updated */
+ SDL_bool updating;
+
struct _SDL_HIDAPI_Device *next;
} SDL_HIDAPI_Device;