From aa2e2f4843567cfe4e6f2f4ffa3f0b74dd98f1ba Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 22 Sep 2022 18:22:17 -0700 Subject: [PATCH] Make sure HID devices can be opened before making them available to the application This prevents a number of issues where devices are enumerated but not actually able to be opened, like https://github.com/libsdl-org/SDL/issues/5781. We currently leave the devices open, allowing us to more easily do controller feature detection, protocol negotiation, detect dropped Bluetooth connections, etc. with the expectation that the application is likely to open the controllers shortly. --- src/hidapi/mac/hid.c | 12 +- src/joystick/hidapi/SDL_hidapi_combined.c | 7 - src/joystick/hidapi/SDL_hidapi_gamecube.c | 47 +-- src/joystick/hidapi/SDL_hidapi_luna.c | 55 ++-- src/joystick/hidapi/SDL_hidapi_ps3.c | 170 +++++----- src/joystick/hidapi/SDL_hidapi_ps4.c | 253 +++++++-------- src/joystick/hidapi/SDL_hidapi_ps5.c | 267 ++++++++------- src/joystick/hidapi/SDL_hidapi_shield.c | 72 ++-- src/joystick/hidapi/SDL_hidapi_stadia.c | 54 ++- src/joystick/hidapi/SDL_hidapi_steam.c | 78 ++--- src/joystick/hidapi/SDL_hidapi_switch.c | 361 ++++++++------------- src/joystick/hidapi/SDL_hidapi_wii.c | 218 +++++-------- src/joystick/hidapi/SDL_hidapi_xbox360.c | 60 ++-- src/joystick/hidapi/SDL_hidapi_xbox360w.c | 37 +-- src/joystick/hidapi/SDL_hidapi_xboxone.c | 116 ++++--- src/joystick/hidapi/SDL_hidapijoystick.c | 72 +++- src/joystick/hidapi/SDL_hidapijoystick_c.h | 4 +- 17 files changed, 811 insertions(+), 1072 deletions(-) diff --git a/src/hidapi/mac/hid.c b/src/hidapi/mac/hid.c index 4ea6bdb6a..35ca38037 100644 --- a/src/hidapi/mac/hid.c +++ b/src/hidapi/mac/hid.c @@ -130,7 +130,6 @@ struct hid_device_list_node static IOHIDManagerRef hid_mgr = 0x0; static struct hid_device_list_node *device_list = 0x0; -static int hid_input_monitoring_denied = 0; static hid_device *new_hid_device(void) { @@ -522,11 +521,7 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, /* Set up the HID Manager if it hasn't been done */ if (hid_init() < 0) return NULL; - - /* If we don't have permission to open devices, don't enumerate them */ - if (hid_input_monitoring_denied) - return NULL; - + /* give the IOHIDManager a chance to update itself */ process_pending_events(); @@ -867,11 +862,6 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive) return dev; } - else if (ret == kIOReturnNotPermitted) { - /* This application doesn't have input monitoring permissions */ - hid_input_monitoring_denied = 1; - goto return_error; - } else { goto return_error; } diff --git a/src/joystick/hidapi/SDL_hidapi_combined.c b/src/joystick/hidapi/SDL_hidapi_combined.c index 04710b45e..df092404c 100644 --- a/src/joystick/hidapi/SDL_hidapi_combined.c +++ b/src/joystick/hidapi/SDL_hidapi_combined.c @@ -52,12 +52,6 @@ HIDAPI_DriverCombined_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *n return SDL_FALSE; } -static const char * -HIDAPI_DriverCombined_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id) -{ - return NULL; -} - static SDL_bool HIDAPI_DriverCombined_InitDevice(SDL_HIDAPI_Device *device) { @@ -241,7 +235,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverCombined = HIDAPI_DriverCombined_UnregisterHints, HIDAPI_DriverCombined_IsEnabled, HIDAPI_DriverCombined_IsSupportedDevice, - HIDAPI_DriverCombined_GetDeviceName, HIDAPI_DriverCombined_InitDevice, HIDAPI_DriverCombined_GetDevicePlayerIndex, HIDAPI_DriverCombined_SetDevicePlayerIndex, diff --git a/src/joystick/hidapi/SDL_hidapi_gamecube.c b/src/joystick/hidapi/SDL_hidapi_gamecube.c index bbd7a05cb..d3bd2cb22 100644 --- a/src/joystick/hidapi/SDL_hidapi_gamecube.c +++ b/src/joystick/hidapi/SDL_hidapi_gamecube.c @@ -89,12 +89,6 @@ HIDAPI_DriverGameCube_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *n return SDL_FALSE; } -static const char * -HIDAPI_DriverGameCube_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id) -{ - return "Nintendo GameCube Controller"; -} - static void ResetAxisRange(SDL_DriverGameCube_Context *ctx, int joystick_index) { @@ -151,18 +145,13 @@ HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device) SDL_EnableGameCubeAdaptors(); #endif + HIDAPI_SetDeviceName(device, "Nintendo GameCube Controller"); + ctx = (SDL_DriverGameCube_Context *)SDL_calloc(1, sizeof(*ctx)); if (!ctx) { SDL_OutOfMemory(); return SDL_FALSE; } - - device->dev = SDL_hid_open_path(device->path, 0); - if (!device->dev) { - SDL_free(ctx); - SDL_SetError("Couldn't open %s", device->path); - return SDL_FALSE; - } device->context = ctx; ctx->joysticks[0] = -1; @@ -184,8 +173,9 @@ HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device) } else { /* This is all that's needed to initialize the device. Really! */ if (SDL_hid_write(device->dev, &initMagic, sizeof(initMagic)) != sizeof(initMagic)) { - SDL_SetError("Couldn't initialize WUP-028"); - goto error; + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + "HIDAPI_DriverGameCube_InitDevice(): Couldn't initialize WUP-028"); + return SDL_FALSE; } /* Wait for the adapter to initialize */ @@ -230,22 +220,6 @@ HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device) SDL_GameControllerButtonReportingHintChanged, ctx); return SDL_TRUE; - -error: - SDL_LockMutex(device->dev_lock); - { - if (device->dev) { - SDL_hid_close(device->dev); - device->dev = NULL; - } - if (device->context) { - SDL_free(device->context); - device->context = NULL; - } - } - SDL_UnlockMutex(device->dev_lock); - - return SDL_FALSE; } static int @@ -565,16 +539,6 @@ HIDAPI_DriverGameCube_FreeDevice(SDL_HIDAPI_Device *device) SDL_GameControllerButtonReportingHintChanged, ctx); SDL_DelHintCallback(SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE, SDL_JoystickGameCubeRumbleBrakeHintChanged, ctx); - - SDL_LockMutex(device->dev_lock); - { - SDL_hid_close(device->dev); - device->dev = NULL; - - SDL_free(device->context); - device->context = NULL; - } - SDL_UnlockMutex(device->dev_lock); } SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube = @@ -585,7 +549,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube = HIDAPI_DriverGameCube_UnregisterHints, HIDAPI_DriverGameCube_IsEnabled, HIDAPI_DriverGameCube_IsSupportedDevice, - HIDAPI_DriverGameCube_GetDeviceName, HIDAPI_DriverGameCube_InitDevice, HIDAPI_DriverGameCube_GetDevicePlayerIndex, HIDAPI_DriverGameCube_SetDevicePlayerIndex, diff --git a/src/joystick/hidapi/SDL_hidapi_luna.c b/src/joystick/hidapi/SDL_hidapi_luna.c index 7808052a8..0f8cfd488 100644 --- a/src/joystick/hidapi/SDL_hidapi_luna.c +++ b/src/joystick/hidapi/SDL_hidapi_luna.c @@ -72,15 +72,20 @@ HIDAPI_DriverLuna_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, return (type == SDL_CONTROLLER_TYPE_AMAZON_LUNA) ? SDL_TRUE : SDL_FALSE; } -static const char * -HIDAPI_DriverLuna_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id) -{ - return "Amazon Luna Controller"; -} - static SDL_bool HIDAPI_DriverLuna_InitDevice(SDL_HIDAPI_Device *device) { + SDL_DriverLuna_Context *ctx; + + HIDAPI_SetDeviceName(device, "Amazon Luna Controller"); + + ctx = (SDL_DriverLuna_Context *)SDL_calloc(1, sizeof(*ctx)); + if (!ctx) { + SDL_OutOfMemory(); + return SDL_FALSE; + } + device->context = ctx; + return HIDAPI_JoystickConnected(device, NULL); } @@ -98,27 +103,14 @@ HIDAPI_DriverLuna_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID static SDL_bool HIDAPI_DriverLuna_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - SDL_DriverLuna_Context *ctx; + SDL_DriverLuna_Context *ctx = (SDL_DriverLuna_Context *)device->context; - ctx = (SDL_DriverLuna_Context *)SDL_calloc(1, sizeof(*ctx)); - if (!ctx) { - SDL_OutOfMemory(); - return SDL_FALSE; - } - - device->dev = SDL_hid_open_path(device->path, 0); - if (!device->dev) { - SDL_SetError("Couldn't open %s", device->path); - SDL_free(ctx); - return SDL_FALSE; - } - device->context = ctx; + SDL_zeroa(ctx->last_state); /* Initialize the joystick capabilities */ joystick->nbuttons = SDL_CONTROLLER_NUM_LUNA_BUTTONS; joystick->naxes = SDL_CONTROLLER_AXIS_MAX; joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL; - joystick->serial = NULL; return SDL_TRUE; } @@ -406,8 +398,7 @@ HIDAPI_DriverLuna_UpdateDevice(SDL_HIDAPI_Device *device) if (device->num_joysticks > 0) { joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); - } - if (!joystick) { + } else { return SDL_FALSE; } @@ -415,6 +406,10 @@ HIDAPI_DriverLuna_UpdateDevice(SDL_HIDAPI_Device *device) #ifdef DEBUG_LUNA_PROTOCOL HIDAPI_DumpPacket("Amazon Luna packet: size = %d", data, size); #endif + if (!joystick) { + continue; + } + switch (size) { case 10: HIDAPI_DriverLuna_HandleUSBStatePacket(joystick, ctx, data, size); @@ -427,7 +422,7 @@ HIDAPI_DriverLuna_UpdateDevice(SDL_HIDAPI_Device *device) if (size < 0) { /* Read error, device is disconnected */ - HIDAPI_JoystickDisconnected(device, joystick->instance_id); + HIDAPI_JoystickDisconnected(device, device->joysticks[0]); } return (size >= 0); } @@ -435,17 +430,6 @@ HIDAPI_DriverLuna_UpdateDevice(SDL_HIDAPI_Device *device) static void HIDAPI_DriverLuna_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - SDL_LockMutex(device->dev_lock); - { - if (device->dev) { - SDL_hid_close(device->dev); - device->dev = NULL; - } - - SDL_free(device->context); - device->context = NULL; - } - SDL_UnlockMutex(device->dev_lock); } static void @@ -461,7 +445,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverLuna = HIDAPI_DriverLuna_UnregisterHints, HIDAPI_DriverLuna_IsEnabled, HIDAPI_DriverLuna_IsSupportedDevice, - HIDAPI_DriverLuna_GetDeviceName, HIDAPI_DriverLuna_InitDevice, HIDAPI_DriverLuna_GetDevicePlayerIndex, HIDAPI_DriverLuna_SetDevicePlayerIndex, diff --git a/src/joystick/hidapi/SDL_hidapi_ps3.c b/src/joystick/hidapi/SDL_hidapi_ps3.c index 1af5c9b77..99bb613ce 100644 --- a/src/joystick/hidapi/SDL_hidapi_ps3.c +++ b/src/joystick/hidapi/SDL_hidapi_ps3.c @@ -52,10 +52,10 @@ typedef struct { SDL_bool is_shanwan; SDL_bool report_sensors; SDL_bool effects_updated; - Uint8 last_state[USB_PACKET_LENGTH]; int player_index; Uint8 rumble_left; Uint8 rumble_right; + Uint8 last_state[USB_PACKET_LENGTH]; } SDL_DriverPS3_Context; @@ -76,16 +76,16 @@ HIDAPI_DriverPS3_UnregisterHints(SDL_HintCallback callback, void *userdata) static SDL_bool HIDAPI_DriverPS3_IsEnabled(void) { + SDL_bool default_value; + #if defined(__MACOSX__) /* This works well on macOS */ - return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3, - SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, - SDL_HIDAPI_DEFAULT)); + default_value = SDL_TRUE; #elif defined(__WINDOWS__) /* You can't initialize the controller with the stock Windows drivers * See https://github.com/ViGEm/DsHidMini as an alternative driver */ - return SDL_FALSE; + default_value = SDL_FALSE; #elif defined(__LINUX__) /* Linux drivers do a better job of managing the transition between * USB and Bluetooth. There are also some quirks in communicating @@ -93,11 +93,16 @@ HIDAPI_DriverPS3_IsEnabled(void) * for libusb, but are not possible to support using hidraw if the * kernel doesn't already know about them. */ - return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3, SDL_FALSE); + default_value = SDL_FALSE; #else /* Untested, default off */ - return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3, SDL_FALSE); + default_value = SDL_FALSE; #endif + + if (default_value) { + default_value = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT); + } + return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3, default_value); } static SDL_bool @@ -112,19 +117,6 @@ HIDAPI_DriverPS3_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, return SDL_FALSE; } -static const char * -HIDAPI_DriverPS3_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id) -{ - if (vendor_id == USB_VENDOR_SONY) { - if (name && SDL_strncasecmp(name, "ShanWan", 7) == 0) { - return "ShanWan PS3 Controller"; - } else { - return "PS3 Controller"; - } - } - return NULL; -} - static int ReadFeatureReport(SDL_hid_device *dev, Uint8 report_id, Uint8 *report, size_t length) { SDL_memset(report, 0, length); @@ -140,6 +132,63 @@ static int SendFeatureReport(SDL_hid_device *dev, Uint8 *report, size_t length) static SDL_bool HIDAPI_DriverPS3_InitDevice(SDL_HIDAPI_Device *device) { + SDL_DriverPS3_Context *ctx; + + if (device->vendor_id == USB_VENDOR_SONY) { + if (SDL_strncasecmp(device->name, "ShanWan", 7) == 0) { + HIDAPI_SetDeviceName(device, "ShanWan PS3 Controller"); + } else { + HIDAPI_SetDeviceName(device, "PS3 Controller"); + } + } + + ctx = (SDL_DriverPS3_Context *)SDL_calloc(1, sizeof(*ctx)); + if (!ctx) { + SDL_OutOfMemory(); + return SDL_FALSE; + } + ctx->device = device; + + device->context = ctx; + + if (SDL_strncasecmp(device->name, "ShanWan", 7) == 0) { + ctx->is_shanwan = SDL_TRUE; + } + + /* Set the controller into report mode over Bluetooth */ + { + Uint8 data[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 }; + + SendFeatureReport(device->dev, data, sizeof(data)); + } + + /* Set the controller into report mode over USB */ + { + Uint8 data[USB_PACKET_LENGTH]; + int size; + + if ((size = ReadFeatureReport(device->dev, 0xf2, data, 17)) < 0) { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + "HIDAPI_DriverPS3_InitDevice(): Couldn't read feature report 0xf2"); + return SDL_FALSE; + } +#ifdef DEBUG_PS3_PROTOCOL + HIDAPI_DumpPacket("PS3 0xF2 packet: size = %d", data, size); +#endif + if ((size = ReadFeatureReport(device->dev, 0xf5, data, 8)) < 0) { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + "HIDAPI_DriverPS3_InitDevice(): Couldn't read feature report 0xf5"); + return SDL_FALSE; + } +#ifdef DEBUG_PS3_PROTOCOL + HIDAPI_DumpPacket("PS3 0xF5 packet: size = %d", data, size); +#endif + if (!ctx->is_shanwan) { + /* An output report could cause ShanWan controllers to rumble non-stop */ + SDL_hid_write(device->dev, data, 1); + } + } + return HIDAPI_JoystickConnected(device, NULL); } @@ -190,59 +239,13 @@ HIDAPI_DriverPS3_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID static SDL_bool HIDAPI_DriverPS3_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - SDL_DriverPS3_Context *ctx; + SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; - ctx = (SDL_DriverPS3_Context *)SDL_calloc(1, sizeof(*ctx)); - if (!ctx) { - SDL_OutOfMemory(); - return SDL_FALSE; - } - ctx->device = device; ctx->joystick = joystick; - - device->dev = SDL_hid_open_path(device->path, 0); - if (!device->dev) { - SDL_free(ctx); - SDL_SetError("Couldn't open %s", device->path); - return SDL_FALSE; - } - device->context = ctx; - - if (SDL_strncasecmp(device->name, "ShanWan", 7) == 0) { - ctx->is_shanwan = SDL_TRUE; - } - - /* Set the controller into report mode over Bluetooth */ - { - Uint8 data[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 }; - - SendFeatureReport(device->dev, data, sizeof(data)); - } - - /* Set the controller into report mode over USB */ - { - Uint8 data[USB_PACKET_LENGTH]; - int size; - - if ((size = ReadFeatureReport(device->dev, 0xf2, data, 17)) < 0) { - SDL_SetError("Couldn't read feature report 0xf2"); - return SDL_FALSE; - } -#ifdef DEBUG_PS3_PROTOCOL - HIDAPI_DumpPacket("PS3 0xF2 packet: size = %d", data, size); -#endif - if ((size = ReadFeatureReport(device->dev, 0xf5, data, 8)) < 0) { - SDL_SetError("Couldn't read feature report 0xf5"); - return SDL_FALSE; - } -#ifdef DEBUG_PS3_PROTOCOL - HIDAPI_DumpPacket("PS3 0xF5 packet: size = %d", data, size); -#endif - if (!ctx->is_shanwan) { - /* An output report could cause ShanWan controllers to rumble non-stop */ - SDL_hid_write(device->dev, data, 1); - } - } + ctx->effects_updated = SDL_FALSE; + ctx->rumble_left = 0; + ctx->rumble_right = 0; + SDL_zeroa(ctx->last_state); /* Initialize player index (needed for setting LEDs) */ ctx->player_index = SDL_JoystickGetPlayerIndex(joystick); @@ -498,8 +501,7 @@ HIDAPI_DriverPS3_UpdateDevice(SDL_HIDAPI_Device *device) if (device->num_joysticks > 0) { joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); - } - if (!joystick) { + } else { return SDL_FALSE; } @@ -507,10 +509,19 @@ HIDAPI_DriverPS3_UpdateDevice(SDL_HIDAPI_Device *device) #ifdef DEBUG_PS3_PROTOCOL HIDAPI_DumpPacket("PS3 packet: size = %d", data, size); #endif + if (!joystick) { + continue; + } if (size == 7) { /* Seen on a ShanWan PS2 -> PS3 USB converter */ HIDAPI_DriverPS3_HandleMiniStatePacket(joystick, ctx, data, size); + + /* Wait for the first report to set the LED state after the controller stops blinking */ + if (!ctx->effects_updated) { + HIDAPI_DriverPS3_UpdateEffects(device); + ctx->effects_updated = SDL_TRUE; + } continue; } @@ -538,7 +549,7 @@ HIDAPI_DriverPS3_UpdateDevice(SDL_HIDAPI_Device *device) if (size < 0) { /* Read error, device is disconnected */ - HIDAPI_JoystickDisconnected(device, joystick->instance_id); + HIDAPI_JoystickDisconnected(device, device->joysticks[0]); } return (size >= 0); } @@ -546,15 +557,9 @@ HIDAPI_DriverPS3_UpdateDevice(SDL_HIDAPI_Device *device) static void HIDAPI_DriverPS3_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - SDL_LockMutex(device->dev_lock); - { - SDL_hid_close(device->dev); - device->dev = NULL; + SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; - SDL_free(device->context); - device->context = NULL; - } - SDL_UnlockMutex(device->dev_lock); + ctx->joystick = NULL; } static void @@ -570,7 +575,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS3 = HIDAPI_DriverPS3_UnregisterHints, HIDAPI_DriverPS3_IsEnabled, HIDAPI_DriverPS3_IsSupportedDevice, - HIDAPI_DriverPS3_GetDeviceName, HIDAPI_DriverPS3_InitDevice, HIDAPI_DriverPS3_GetDevicePlayerIndex, HIDAPI_DriverPS3_SetDevicePlayerIndex, diff --git a/src/joystick/hidapi/SDL_hidapi_ps4.c b/src/joystick/hidapi/SDL_hidapi_ps4.c index e927ec7b3..1fe59375b 100644 --- a/src/joystick/hidapi/SDL_hidapi_ps4.c +++ b/src/joystick/hidapi/SDL_hidapi_ps4.c @@ -142,8 +142,6 @@ typedef struct { Uint8 led_red; Uint8 led_green; Uint8 led_blue; - Uint8 volume; - Uint32 last_volume_check; PS4StatePacket_t last_state; } SDL_DriverPS4_Context; @@ -176,15 +174,6 @@ HIDAPI_DriverPS4_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, return (type == SDL_CONTROLLER_TYPE_PS4) ? SDL_TRUE : SDL_FALSE; } -static const char * -HIDAPI_DriverPS4_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id) -{ - if (vendor_id == USB_VENDOR_SONY) { - return "PS4 Controller"; - } - return NULL; -} - static int ReadFeatureReport(SDL_hid_device *dev, Uint8 report_id, Uint8 *report, size_t length) { SDL_memset(report, 0, length); @@ -222,6 +211,106 @@ SetLedsForPlayerIndex(DS4EffectsState_t *effects, int player_index) static SDL_bool HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device) { + SDL_DriverPS4_Context *ctx; + Uint8 data[USB_PACKET_LENGTH]; + int size; + char serial[18]; + + if (device->vendor_id == USB_VENDOR_SONY) { + HIDAPI_SetDeviceName(device, "PS4 Controller"); + } + + ctx = (SDL_DriverPS4_Context *)SDL_calloc(1, sizeof(*ctx)); + if (!ctx) { + SDL_OutOfMemory(); + return SDL_FALSE; + } + ctx->device = device; + + device->context = ctx; + + if (device->serial && SDL_strlen(device->serial) == 12) { + int i, j; + + j = -1; + for (i = 0; i < 12; i += 2) { + j += 1; + SDL_memcpy(&serial[j], &device->serial[i], 2); + j += 2; + serial[j] = '-'; + } + serial[j] = '\0'; + } else { + serial[0] = '\0'; + } + + /* Check for type of connection */ + ctx->is_dongle = (device->vendor_id == USB_VENDOR_SONY && device->product_id == USB_PRODUCT_SONY_DS4_DONGLE); + if (ctx->is_dongle) { + ctx->is_bluetooth = SDL_FALSE; + ctx->official_controller = SDL_TRUE; + ctx->enhanced_mode = SDL_TRUE; + } else if (device->vendor_id == USB_VENDOR_SONY) { + /* This will fail if we're on Bluetooth */ + size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdSerialNumber, data, sizeof(data)); + if (size >= 7) { + SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", + data[6], data[5], data[4], data[3], data[2], data[1]); + ctx->is_bluetooth = SDL_FALSE; + ctx->enhanced_mode = SDL_TRUE; + } else { + ctx->is_bluetooth = SDL_TRUE; + + /* Read a report to see if we're in enhanced mode */ + size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 16); +#ifdef DEBUG_PS4_PROTOCOL + if (size > 0) { + HIDAPI_DumpPacket("PS4 first packet: size = %d", data, size); + } else { + SDL_Log("PS4 first packet: size = %d\n", size); + } +#endif + if (size > 0 && + data[0] >= k_EPS4ReportIdBluetoothState1 && + data[0] <= k_EPS4ReportIdBluetoothState9) { + ctx->enhanced_mode = SDL_TRUE; + } + } + ctx->official_controller = SDL_TRUE; + } else { + /* Third party controllers appear to all be wired */ + ctx->is_bluetooth = SDL_FALSE; + ctx->enhanced_mode = SDL_TRUE; + } +#ifdef DEBUG_PS4 + SDL_Log("PS4 dongle = %s, bluetooth = %s\n", ctx->is_dongle ? "TRUE" : "FALSE", ctx->is_bluetooth ? "TRUE" : "FALSE"); +#endif + + /* Get the device capabilities */ + if (device->vendor_id == USB_VENDOR_SONY) { + ctx->effects_supported = SDL_TRUE; + ctx->sensors_supported = SDL_TRUE; + ctx->touchpad_supported = SDL_TRUE; + } else if ((size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdCapabilities, data, sizeof(data))) == 48 && + data[2] == 0x27) { + Uint8 capabilities = data[4]; + +#ifdef DEBUG_PS4_PROTOCOL + HIDAPI_DumpPacket("PS4 capabilities: size = %d", data, size); +#endif + if ((capabilities & 0x0C) != 0) { + ctx->effects_supported = SDL_TRUE; + } + if ((capabilities & 0x02) != 0) { + ctx->sensors_supported = SDL_TRUE; + } + if ((capabilities & 0x40) != 0) { + ctx->touchpad_supported = SDL_TRUE; + } + } + + HIDAPI_SetDeviceSerial(device, serial); + return HIDAPI_JoystickConnected(device, NULL); } @@ -471,7 +560,7 @@ HIDAPI_DriverPS4_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID { SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context; - if (!ctx) { + if (!ctx->joystick) { return; } @@ -484,124 +573,28 @@ HIDAPI_DriverPS4_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID static SDL_bool HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - SDL_DriverPS4_Context *ctx; - Uint8 data[USB_PACKET_LENGTH]; - int size; - SDL_bool enhanced_mode = SDL_FALSE; + SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *) device->context; - ctx = (SDL_DriverPS4_Context *)SDL_calloc(1, sizeof(*ctx)); - if (!ctx) { - SDL_OutOfMemory(); - return SDL_FALSE; - } - ctx->device = device; ctx->joystick = joystick; ctx->last_packet = SDL_GetTicks(); - - device->dev = SDL_hid_open_path(device->path, 0); - if (!device->dev) { - SDL_free(ctx); - SDL_SetError("Couldn't open %s", device->path); - return SDL_FALSE; - } - device->context = ctx; - - /* Check for type of connection */ - ctx->is_dongle = (device->vendor_id == USB_VENDOR_SONY && device->product_id == USB_PRODUCT_SONY_DS4_DONGLE); - if (ctx->is_dongle) { - ctx->is_bluetooth = SDL_FALSE; - ctx->official_controller = SDL_TRUE; - enhanced_mode = SDL_TRUE; - } else if (device->vendor_id == USB_VENDOR_SONY) { - /* This will fail if we're on Bluetooth */ - size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdSerialNumber, data, sizeof(data)); - if (size >= 7) { - char serial[18]; - - SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", - data[6], data[5], data[4], data[3], data[2], data[1]); - joystick->serial = SDL_strdup(serial); - ctx->is_bluetooth = SDL_FALSE; - enhanced_mode = SDL_TRUE; - } else { - ctx->is_bluetooth = SDL_TRUE; - - /* Read a report to see if we're in enhanced mode */ - size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 16); -#ifdef DEBUG_PS4_PROTOCOL - if (size > 0) { - HIDAPI_DumpPacket("PS4 first packet: size = %d", data, size); - } else { - SDL_Log("PS4 first packet: size = %d\n", size); - } -#endif - if (size > 0 && - data[0] >= k_EPS4ReportIdBluetoothState1 && - data[0] <= k_EPS4ReportIdBluetoothState9) { - enhanced_mode = SDL_TRUE; - } - } - ctx->official_controller = SDL_TRUE; - } else { - /* Third party controllers appear to all be wired */ - ctx->is_bluetooth = SDL_FALSE; - enhanced_mode = SDL_TRUE; - } -#ifdef DEBUG_PS4 - SDL_Log("PS4 dongle = %s, bluetooth = %s\n", ctx->is_dongle ? "TRUE" : "FALSE", ctx->is_bluetooth ? "TRUE" : "FALSE"); -#endif - - /* Get the device capabilities */ - if (device->vendor_id == USB_VENDOR_SONY) { - ctx->effects_supported = SDL_TRUE; - ctx->sensors_supported = SDL_TRUE; - ctx->touchpad_supported = SDL_TRUE; - } else if ((size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdCapabilities, data, sizeof(data))) == 48 && - data[2] == 0x27) { - Uint8 capabilities = data[4]; - -#ifdef DEBUG_PS4_PROTOCOL - HIDAPI_DumpPacket("PS4 capabilities: size = %d", data, size); -#endif - if ((capabilities & 0x0C) != 0) { - ctx->effects_supported = SDL_TRUE; - } - if ((capabilities & 0x02) != 0) { - ctx->sensors_supported = SDL_TRUE; - } - if ((capabilities & 0x40) != 0) { - ctx->touchpad_supported = SDL_TRUE; - } - } - - if (!joystick->serial && device->serial && SDL_strlen(device->serial) == 12) { - int i, j; - char serial[18]; - - j = -1; - for (i = 0; i < 12; i += 2) { - j += 1; - SDL_memcpy(&serial[j], &device->serial[i], 2); - j += 2; - serial[j] = '-'; - } - serial[j] = '\0'; - - joystick->serial = SDL_strdup(serial); - } + ctx->report_sensors = SDL_FALSE; + ctx->report_touchpad = SDL_FALSE; + ctx->rumble_left = 0; + ctx->rumble_right = 0; + ctx->color_set = SDL_FALSE; + SDL_zero(ctx->last_state); /* Initialize player index (needed for setting LEDs) */ ctx->player_index = SDL_JoystickGetPlayerIndex(joystick); - /* Initialize the joystick capabilities - * - * We can't dynamically add the touchpad button, so always report it here - */ - joystick->nbuttons = 16; + /* Initialize the joystick capabilities */ + joystick->nbuttons = ctx->touchpad_supported ? 16 : 15; joystick->naxes = SDL_CONTROLLER_AXIS_MAX; joystick->epowerlevel = ctx->is_bluetooth ? SDL_JOYSTICK_POWER_UNKNOWN : SDL_JOYSTICK_POWER_WIRED; - if (enhanced_mode) { + if (ctx->enhanced_mode) { + /* Force initialization when opening the joystick */ + ctx->enhanced_mode = SDL_FALSE; HIDAPI_DriverPS4_SetEnhancedMode(device, joystick); } else { SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, @@ -879,8 +872,7 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device) if (device->num_joysticks > 0) { joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); - } - if (!joystick) { + } else { return SDL_FALSE; } @@ -891,6 +883,10 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device) ++packet_count; ctx->last_packet = SDL_GetTicks(); + if (!joystick) { + continue; + } + switch (data[0]) { case k_EPS4ReportIdUsbState: HIDAPI_DriverPS4_HandleStatePacket(joystick, device->dev, ctx, (PS4StatePacket_t *)&data[1]); @@ -931,7 +927,7 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device) if (size < 0) { /* Read error, device is disconnected */ - HIDAPI_JoystickDisconnected(device, joystick->instance_id); + HIDAPI_JoystickDisconnected(device, device->joysticks[0]); } return (size >= 0); } @@ -944,15 +940,7 @@ HIDAPI_DriverPS4_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, SDL_PS4RumbleHintChanged, ctx); - SDL_LockMutex(device->dev_lock); - { - SDL_hid_close(device->dev); - device->dev = NULL; - - SDL_free(device->context); - device->context = NULL; - } - SDL_UnlockMutex(device->dev_lock); + ctx->joystick = NULL; } static void @@ -968,7 +956,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4 = HIDAPI_DriverPS4_UnregisterHints, HIDAPI_DriverPS4_IsEnabled, HIDAPI_DriverPS4_IsSupportedDevice, - HIDAPI_DriverPS4_GetDeviceName, HIDAPI_DriverPS4_InitDevice, HIDAPI_DriverPS4_GetDevicePlayerIndex, HIDAPI_DriverPS4_SetDevicePlayerIndex, diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c index bb03cbf8a..638bc4491 100644 --- a/src/joystick/hidapi/SDL_hidapi_ps5.c +++ b/src/joystick/hidapi/SDL_hidapi_ps5.c @@ -256,15 +256,6 @@ HIDAPI_DriverPS5_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, return (type == SDL_CONTROLLER_TYPE_PS5) ? SDL_TRUE : SDL_FALSE; } -static const char * -HIDAPI_DriverPS5_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id) -{ - if (vendor_id == USB_VENDOR_SONY) { - return "PS5 Controller"; - } - return NULL; -} - static int ReadFeatureReport(SDL_hid_device *dev, Uint8 report_id, Uint8 *report, size_t length) { SDL_memset(report, 0, length); @@ -321,6 +312,112 @@ SetLightsForPlayerIndex(DS5EffectsState_t *effects, int player_index) static SDL_bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device) { + SDL_DriverPS5_Context *ctx; + Uint8 data[USB_PACKET_LENGTH*2]; + int size; + char serial[18]; + + if (device->vendor_id == USB_VENDOR_SONY) { + HIDAPI_SetDeviceName(device, "PS5 Controller"); + } + + ctx = (SDL_DriverPS5_Context *)SDL_calloc(1, sizeof(*ctx)); + if (!ctx) { + SDL_OutOfMemory(); + return SDL_FALSE; + } + ctx->device = device; + + device->context = ctx; + + if (device->serial && SDL_strlen(device->serial) == 12) { + int i, j; + + j = -1; + for (i = 0; i < 12; i += 2) { + j += 1; + SDL_memcpy(&serial[j], &device->serial[i], 2); + j += 2; + serial[j] = '-'; + } + serial[j] = '\0'; + } else { + serial[0] = '\0'; + } + + /* Read a report to see what mode we're in */ + size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 16); +#ifdef DEBUG_PS5_PROTOCOL + if (size > 0) { + HIDAPI_DumpPacket("PS5 first packet: size = %d", data, size); + } else { + SDL_Log("PS5 first packet: size = %d\n", size); + } +#endif + if (size == 64) { + /* Connected over USB */ + ctx->is_bluetooth = SDL_FALSE; + ctx->enhanced_mode = SDL_TRUE; + } else if (size > 0 && data[0] == k_EPS5ReportIdBluetoothEffects) { + /* Connected over Bluetooth, using enhanced reports */ + ctx->is_bluetooth = SDL_TRUE; + ctx->enhanced_mode = SDL_TRUE; + } else { + /* Connected over Bluetooth, using simple reports (DirectInput enabled) */ + ctx->is_bluetooth = SDL_TRUE; + + /* Games written prior the introduction of PS5 controller support in SDL will not be aware of + SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, but they did know SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE. + To support apps that only knew about the PS4 hint, we'll use the PS4 hint as the default. + */ + ctx->enhanced_mode = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, + SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, SDL_FALSE)); + } + + if (ctx->enhanced_mode) { + /* Read the serial number (Bluetooth address in reverse byte order) + This will also enable enhanced reports over Bluetooth + */ + if (ReadFeatureReport(device->dev, k_EPS5FeatureReportIdSerialNumber, data, sizeof(data)) >= 7) { + SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", + data[6], data[5], data[4], data[3], data[2], data[1]); + } + + /* Read the firmware version + This will also enable enhanced reports over Bluetooth + */ + if (ReadFeatureReport(device->dev, k_EPS5FeatureReportIdFirmwareInfo, data, USB_PACKET_LENGTH) >= 46) { + ctx->firmware_version = (Uint16)data[44] | ((Uint16)data[45] << 8); + } + } + + /* Get the device capabilities */ + if (device->vendor_id == USB_VENDOR_SONY) { + ctx->effects_supported = SDL_TRUE; + ctx->sensors_supported = SDL_TRUE; + ctx->touchpad_supported = SDL_TRUE; + } else if ((size = ReadFeatureReport(device->dev, k_EPS5FeatureReportIdCapabilities, data, sizeof(data))) == 48 && + data[2] == 0x28) { + Uint8 capabilities = data[4]; + +#ifdef DEBUG_PS5_PROTOCOL + HIDAPI_DumpPacket("PS5 capabilities: size = %d", data, size); +#endif + if ((capabilities & 0x0C) != 0) { + ctx->effects_supported = SDL_TRUE; + } + if ((capabilities & 0x02) != 0) { + ctx->sensors_supported = SDL_TRUE; + } + if ((capabilities & 0x40) != 0) { + ctx->touchpad_supported = SDL_TRUE; + } + + ctx->use_alternate_report = SDL_TRUE; + } + + HIDAPI_SetDeviceSerial(device, serial); + return HIDAPI_JoystickConnected(device, NULL); } @@ -623,7 +720,7 @@ HIDAPI_DriverPS5_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID { SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; - if (!ctx) { + if (!ctx->joystick) { return; } @@ -636,132 +733,31 @@ HIDAPI_DriverPS5_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID static SDL_bool HIDAPI_DriverPS5_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - SDL_DriverPS5_Context *ctx; - Uint8 data[USB_PACKET_LENGTH*2]; - int size; - SDL_bool enhanced_mode = SDL_FALSE; + SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; - ctx = (SDL_DriverPS5_Context *)SDL_calloc(1, sizeof(*ctx)); - if (!ctx) { - SDL_OutOfMemory(); - return SDL_FALSE; - } - ctx->device = device; ctx->joystick = joystick; ctx->last_packet = SDL_GetTicks(); - - device->dev = SDL_hid_open_path(device->path, 0); - if (!device->dev) { - SDL_free(ctx); - SDL_SetError("Couldn't open %s", device->path); - return SDL_FALSE; - } - device->context = ctx; - - /* Read a report to see what mode we're in */ - size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 16); -#ifdef DEBUG_PS5_PROTOCOL - if (size > 0) { - HIDAPI_DumpPacket("PS5 first packet: size = %d", data, size); - } else { - SDL_Log("PS5 first packet: size = %d\n", size); - } -#endif - if (size == 64) { - /* Connected over USB */ - ctx->is_bluetooth = SDL_FALSE; - enhanced_mode = SDL_TRUE; - } else if (size > 0 && data[0] == k_EPS5ReportIdBluetoothEffects) { - /* Connected over Bluetooth, using enhanced reports */ - ctx->is_bluetooth = SDL_TRUE; - enhanced_mode = SDL_TRUE; - } else { - /* Connected over Bluetooth, using simple reports (DirectInput enabled) */ - ctx->is_bluetooth = SDL_TRUE; - - /* Games written prior the introduction of PS5 controller support in SDL will not be aware of - SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, but they did know SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE. - To support apps that only knew about the PS4 hint, we'll use the PS4 hint as the default. - */ - enhanced_mode = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, - SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, SDL_FALSE)); - } - - if (enhanced_mode) { - /* Read the serial number (Bluetooth address in reverse byte order) - This will also enable enhanced reports over Bluetooth - */ - if (ReadFeatureReport(device->dev, k_EPS5FeatureReportIdSerialNumber, data, sizeof(data)) >= 7) { - char serial[18]; - - SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", - data[6], data[5], data[4], data[3], data[2], data[1]); - joystick->serial = SDL_strdup(serial); - } - - /* Read the firmware version - This will also enable enhanced reports over Bluetooth - */ - if (ReadFeatureReport(device->dev, k_EPS5FeatureReportIdFirmwareInfo, data, USB_PACKET_LENGTH) >= 46) { - ctx->firmware_version = (Uint16)data[44] | ((Uint16)data[45] << 8); - joystick->firmware_version = ctx->firmware_version; - } - } - - /* Get the device capabilities */ - if (device->vendor_id == USB_VENDOR_SONY) { - ctx->effects_supported = SDL_TRUE; - ctx->sensors_supported = SDL_TRUE; - ctx->touchpad_supported = SDL_TRUE; - } else if ((size = ReadFeatureReport(device->dev, k_EPS5FeatureReportIdCapabilities, data, sizeof(data))) == 48 && - data[2] == 0x28) { - Uint8 capabilities = data[4]; - -#ifdef DEBUG_PS5_PROTOCOL - HIDAPI_DumpPacket("PS5 capabilities: size = %d", data, size); -#endif - if ((capabilities & 0x0C) != 0) { - ctx->effects_supported = SDL_TRUE; - } - if ((capabilities & 0x02) != 0) { - ctx->sensors_supported = SDL_TRUE; - } - if ((capabilities & 0x40) != 0) { - ctx->touchpad_supported = SDL_TRUE; - } - - ctx->use_alternate_report = SDL_TRUE; - } - - if (!joystick->serial && device->serial && SDL_strlen(device->serial) == 12) { - int i, j; - char serial[18]; - - j = -1; - for (i = 0; i < 12; i += 2) { - j += 1; - SDL_memcpy(&serial[j], &device->serial[i], 2); - j += 2; - serial[j] = '-'; - } - serial[j] = '\0'; - - joystick->serial = SDL_strdup(serial); - } + ctx->report_sensors = SDL_FALSE; + ctx->report_touchpad = SDL_FALSE; + ctx->rumble_left = 0; + ctx->rumble_right = 0; + ctx->color_set = SDL_FALSE; + ctx->led_reset_state = k_EDS5LEDResetStateNone; + SDL_zero(ctx->last_state); /* Initialize player index (needed for setting LEDs) */ ctx->player_index = SDL_JoystickGetPlayerIndex(joystick); ctx->player_lights = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED, SDL_TRUE); - /* Initialize the joystick capabilities - * - * We can't dynamically add the touchpad button, so always report it here - */ - joystick->nbuttons = 17; + /* Initialize the joystick capabilities */ + joystick->nbuttons = ctx->touchpad_supported ? 17 : 15; joystick->naxes = SDL_CONTROLLER_AXIS_MAX; joystick->epowerlevel = ctx->is_bluetooth ? SDL_JOYSTICK_POWER_UNKNOWN : SDL_JOYSTICK_POWER_WIRED; + joystick->firmware_version = ctx->firmware_version; - if (enhanced_mode) { + if (ctx->enhanced_mode) { + /* Force initialization when opening the joystick */ + ctx->enhanced_mode = SDL_FALSE; HIDAPI_DriverPS5_SetEnhancedMode(device, joystick); } else { SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, @@ -769,6 +765,7 @@ HIDAPI_DriverPS5_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) } SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED, SDL_PS5PlayerLEDHintChanged, ctx); + return SDL_TRUE; } @@ -1183,8 +1180,7 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device) if (device->num_joysticks > 0) { joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); - } - if (!joystick) { + } else { return SDL_FALSE; } @@ -1195,6 +1191,10 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device) ++packet_count; ctx->last_packet = SDL_GetTicks(); + if (!joystick) { + continue; + } + switch (data[0]) { case k_EPS5ReportIdState: if (size == 10 || size == 78) { @@ -1241,7 +1241,7 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device) if (size < 0) { /* Read error, device is disconnected */ - HIDAPI_JoystickDisconnected(device, joystick->instance_id); + HIDAPI_JoystickDisconnected(device, device->joysticks[0]); } return (size >= 0); } @@ -1257,15 +1257,7 @@ HIDAPI_DriverPS5_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED, SDL_PS5PlayerLEDHintChanged, ctx); - SDL_LockMutex(device->dev_lock); - { - SDL_hid_close(device->dev); - device->dev = NULL; - - SDL_free(device->context); - device->context = NULL; - } - SDL_UnlockMutex(device->dev_lock); + ctx->joystick = NULL; } static void @@ -1281,7 +1273,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS5 = HIDAPI_DriverPS5_UnregisterHints, HIDAPI_DriverPS5_IsEnabled, HIDAPI_DriverPS5_IsSupportedDevice, - HIDAPI_DriverPS5_GetDeviceName, HIDAPI_DriverPS5_InitDevice, HIDAPI_DriverPS5_GetDevicePlayerIndex, HIDAPI_DriverPS5_SetDevicePlayerIndex, diff --git a/src/joystick/hidapi/SDL_hidapi_shield.c b/src/joystick/hidapi/SDL_hidapi_shield.c index 69ab1a4a0..42cfea1c8 100644 --- a/src/joystick/hidapi/SDL_hidapi_shield.c +++ b/src/joystick/hidapi/SDL_hidapi_shield.c @@ -107,15 +107,20 @@ HIDAPI_DriverShield_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *nam return (type == SDL_CONTROLLER_TYPE_NVIDIA_SHIELD) ? SDL_TRUE : SDL_FALSE; } -static const char * -HIDAPI_DriverShield_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id) -{ - return "NVIDIA SHIELD Controller"; -} - static SDL_bool HIDAPI_DriverShield_InitDevice(SDL_HIDAPI_Device *device) { + SDL_DriverShield_Context *ctx; + + HIDAPI_SetDeviceName(device, "NVIDIA SHIELD Controller"); + + ctx = (SDL_DriverShield_Context *)SDL_calloc(1, sizeof(*ctx)); + if (!ctx) { + SDL_OutOfMemory(); + return SDL_FALSE; + } + device->context = ctx; + return HIDAPI_JoystickConnected(device, NULL); } @@ -133,7 +138,7 @@ HIDAPI_DriverShield_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystick static int HIDAPI_DriverShield_SendCommand(SDL_HIDAPI_Device *device, Uint8 cmd, const void *data, int size) { - SDL_DriverShield_Context *ctx = device->context; + SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context; ShieldCommandReport_t cmd_pkt; if (size > sizeof(cmd_pkt.payload)) { @@ -164,21 +169,14 @@ HIDAPI_DriverShield_SendCommand(SDL_HIDAPI_Device *device, Uint8 cmd, const void static SDL_bool HIDAPI_DriverShield_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - SDL_DriverShield_Context *ctx; + SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context; - ctx = (SDL_DriverShield_Context *)SDL_calloc(1, sizeof(*ctx)); - if (!ctx) { - SDL_OutOfMemory(); - return SDL_FALSE; - } - - device->dev = SDL_hid_open_path(device->path, 0); - if (!device->dev) { - SDL_SetError("Couldn't open %s", device->path); - SDL_free(ctx); - return SDL_FALSE; - } - device->context = ctx; + ctx->rumble_report_pending = SDL_FALSE; + ctx->rumble_update_pending = SDL_FALSE; + ctx->left_motor_amplitude = 0; + ctx->right_motor_amplitude = 0; + ctx->last_rumble_time = 0; + SDL_zeroa(ctx->last_state); /* Initialize the joystick capabilities */ joystick->nbuttons = 16; @@ -186,7 +184,6 @@ HIDAPI_DriverShield_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN; /* Request battery and charging info */ - ctx->battery_level = SDL_JOYSTICK_POWER_UNKNOWN; ctx->last_battery_query_time = SDL_GetTicks(); HIDAPI_DriverShield_SendCommand(device, CMD_CHARGE_STATE, NULL, 0); HIDAPI_DriverShield_SendCommand(device, CMD_BATTERY_STATE, NULL, 0); @@ -367,8 +364,7 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device) if (device->num_joysticks > 0) { joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); - } - if (!joystick) { + } else { return SDL_FALSE; } @@ -376,9 +372,13 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device) #ifdef DEBUG_SHIELD_PROTOCOL HIDAPI_DumpPacket("NVIDIA SHIELD packet: size = %d", data, size); #endif + /* Byte 0 is HID report ID */ switch (data[0]) { case k_ShieldReportIdControllerState: + if (!joystick) { + break; + } HIDAPI_DriverShield_HandleStatePacket(joystick, ctx, data, size); break; case k_ShieldReportIdCommandResponse: @@ -390,7 +390,9 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device) break; case CMD_CHARGE_STATE: ctx->charging = cmd_resp_report->payload[0] != 0; - SDL_PrivateJoystickBatteryLevel(joystick, ctx->charging ? SDL_JOYSTICK_POWER_WIRED : ctx->battery_level); + if (joystick) { + SDL_PrivateJoystickBatteryLevel(joystick, ctx->charging ? SDL_JOYSTICK_POWER_WIRED : ctx->battery_level); + } break; case CMD_BATTERY_STATE: switch (cmd_resp_report->payload[2]) { @@ -412,7 +414,9 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device) ctx->battery_level = SDL_JOYSTICK_POWER_UNKNOWN; break; } - SDL_PrivateJoystickBatteryLevel(joystick, ctx->charging ? SDL_JOYSTICK_POWER_WIRED : ctx->battery_level); + if (joystick) { + SDL_PrivateJoystickBatteryLevel(joystick, ctx->charging ? SDL_JOYSTICK_POWER_WIRED : ctx->battery_level); + } break; } break; @@ -420,7 +424,7 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device) } /* Ask for battery state again if we're due for an update */ - if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->last_battery_query_time + BATTERY_POLL_INTERVAL_MS)) { + if (joystick && SDL_TICKS_PASSED(SDL_GetTicks(), ctx->last_battery_query_time + BATTERY_POLL_INTERVAL_MS)) { ctx->last_battery_query_time = SDL_GetTicks(); HIDAPI_DriverShield_SendCommand(device, CMD_BATTERY_STATE, NULL, 0); } @@ -434,7 +438,7 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device) if (size < 0) { /* Read error, device is disconnected */ - HIDAPI_JoystickDisconnected(device, joystick->instance_id); + HIDAPI_JoystickDisconnected(device, device->joysticks[0]); } return (size >= 0); } @@ -442,17 +446,6 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device) static void HIDAPI_DriverShield_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - SDL_LockMutex(device->dev_lock); - { - if (device->dev) { - SDL_hid_close(device->dev); - device->dev = NULL; - } - - SDL_free(device->context); - device->context = NULL; - } - SDL_UnlockMutex(device->dev_lock); } static void @@ -468,7 +461,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverShield = HIDAPI_DriverShield_UnregisterHints, HIDAPI_DriverShield_IsEnabled, HIDAPI_DriverShield_IsSupportedDevice, - HIDAPI_DriverShield_GetDeviceName, HIDAPI_DriverShield_InitDevice, HIDAPI_DriverShield_GetDevicePlayerIndex, HIDAPI_DriverShield_SetDevicePlayerIndex, diff --git a/src/joystick/hidapi/SDL_hidapi_stadia.c b/src/joystick/hidapi/SDL_hidapi_stadia.c index 23056acff..8b20d75ab 100644 --- a/src/joystick/hidapi/SDL_hidapi_stadia.c +++ b/src/joystick/hidapi/SDL_hidapi_stadia.c @@ -73,15 +73,20 @@ HIDAPI_DriverStadia_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *nam return (type == SDL_CONTROLLER_TYPE_GOOGLE_STADIA) ? SDL_TRUE : SDL_FALSE; } -static const char * -HIDAPI_DriverStadia_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id) -{ - return "Google Stadia Controller"; -} - static SDL_bool HIDAPI_DriverStadia_InitDevice(SDL_HIDAPI_Device *device) { + SDL_DriverStadia_Context *ctx; + + HIDAPI_SetDeviceName(device, "Google Stadia Controller"); + + ctx = (SDL_DriverStadia_Context *)SDL_calloc(1, sizeof(*ctx)); + if (!ctx) { + SDL_OutOfMemory(); + return SDL_FALSE; + } + device->context = ctx; + return HIDAPI_JoystickConnected(device, NULL); } @@ -99,21 +104,9 @@ HIDAPI_DriverStadia_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystick static SDL_bool HIDAPI_DriverStadia_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - SDL_DriverStadia_Context *ctx; + SDL_DriverStadia_Context *ctx = (SDL_DriverStadia_Context *)device->context; - ctx = (SDL_DriverStadia_Context *)SDL_calloc(1, sizeof(*ctx)); - if (!ctx) { - SDL_OutOfMemory(); - return SDL_FALSE; - } - - device->dev = SDL_hid_open_path(device->path, 0); - if (!device->dev) { - SDL_SetError("Couldn't open %s", device->path); - SDL_free(ctx); - return SDL_FALSE; - } - device->context = ctx; + SDL_zeroa(ctx->last_state); /* Initialize the joystick capabilities */ joystick->nbuttons = SDL_CONTROLLER_NUM_STADIA_BUTTONS; @@ -281,8 +274,7 @@ HIDAPI_DriverStadia_UpdateDevice(SDL_HIDAPI_Device *device) if (device->num_joysticks > 0) { joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); - } - if (!joystick) { + } else { return SDL_FALSE; } @@ -290,12 +282,16 @@ HIDAPI_DriverStadia_UpdateDevice(SDL_HIDAPI_Device *device) #ifdef DEBUG_STADIA_PROTOCOL HIDAPI_DumpPacket("Google Stadia packet: size = %d", data, size); #endif + if (!joystick) { + continue; + } + HIDAPI_DriverStadia_HandleStatePacket(joystick, ctx, data, size); } if (size < 0) { /* Read error, device is disconnected */ - HIDAPI_JoystickDisconnected(device, joystick->instance_id); + HIDAPI_JoystickDisconnected(device, device->joysticks[0]); } return (size >= 0); } @@ -303,17 +299,6 @@ HIDAPI_DriverStadia_UpdateDevice(SDL_HIDAPI_Device *device) static void HIDAPI_DriverStadia_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - SDL_LockMutex(device->dev_lock); - { - if (device->dev) { - SDL_hid_close(device->dev); - device->dev = NULL; - } - - SDL_free(device->context); - device->context = NULL; - } - SDL_UnlockMutex(device->dev_lock); } static void @@ -329,7 +314,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverStadia = HIDAPI_DriverStadia_UnregisterHints, HIDAPI_DriverStadia_IsEnabled, HIDAPI_DriverStadia_IsSupportedDevice, - HIDAPI_DriverStadia_GetDeviceName, HIDAPI_DriverStadia_InitDevice, HIDAPI_DriverStadia_GetDevicePlayerIndex, HIDAPI_DriverStadia_SetDevicePlayerIndex, diff --git a/src/joystick/hidapi/SDL_hidapi_steam.c b/src/joystick/hidapi/SDL_hidapi_steam.c index 2faf65c36..64ce13ade 100644 --- a/src/joystick/hidapi/SDL_hidapi_steam.c +++ b/src/joystick/hidapi/SDL_hidapi_steam.c @@ -1022,15 +1022,20 @@ HIDAPI_DriverSteam_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name return SDL_IsJoystickSteamController(vendor_id, product_id); } -static const char * -HIDAPI_DriverSteam_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id) -{ - return "Steam Controller"; -} - static SDL_bool HIDAPI_DriverSteam_InitDevice(SDL_HIDAPI_Device *device) { + SDL_DriverSteam_Context *ctx; + + HIDAPI_SetDeviceName(device, "Steam Controller"); + + ctx = (SDL_DriverSteam_Context *)SDL_calloc(1, sizeof(*ctx)); + if (!ctx) { + SDL_OutOfMemory(); + return SDL_FALSE; + } + device->context = ctx; + return HIDAPI_JoystickConnected(device, NULL); } @@ -1048,27 +1053,18 @@ HIDAPI_DriverSteam_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickI static SDL_bool HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - SDL_DriverSteam_Context *ctx; + SDL_DriverSteam_Context *ctx = (SDL_DriverSteam_Context *)device->context; uint32_t update_rate_in_us = 0; float update_rate_in_hz = 0.0f; - ctx = (SDL_DriverSteam_Context *)SDL_calloc(1, sizeof(*ctx)); - if (!ctx) { - SDL_OutOfMemory(); - goto error; - } - device->context = ctx; - - device->dev = SDL_hid_open_path(device->path, 0); - if (!device->dev) { - SDL_SetError("Couldn't open %s", device->path); - goto error; - } - SDL_hid_set_nonblocking(device->dev, 1); + ctx->report_sensors = SDL_FALSE; + SDL_zero(ctx->m_assembler); + SDL_zero(ctx->m_state); + SDL_zero(ctx->m_last_state); if (!ResetSteamController(device->dev, false, &update_rate_in_us)) { SDL_SetError("Couldn't reset controller"); - goto error; + return SDL_FALSE; } if (update_rate_in_us > 0) { update_rate_in_hz = 1000000.0f / update_rate_in_us; @@ -1084,21 +1080,6 @@ HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystic SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, update_rate_in_hz); return SDL_TRUE; - -error: - SDL_LockMutex(device->dev_lock); - { - if (device->dev) { - SDL_hid_close(device->dev); - device->dev = NULL; - } - if (device->context) { - SDL_free(device->context); - device->context = NULL; - } - } - SDL_UnlockMutex(device->dev_lock); - return SDL_FALSE; } static int @@ -1117,7 +1098,7 @@ HIDAPI_DriverSteam_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystic static Uint32 HIDAPI_DriverSteam_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - /* You should use the full Steam Input API for LED support */ + /* You should use the full Steam Input API for extended capabilities */ return 0; } @@ -1166,8 +1147,7 @@ HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device *device) if (device->num_joysticks > 0) { joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); - } - if (!joystick) { + } else { return SDL_FALSE; } @@ -1178,11 +1158,14 @@ HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device *device) const Uint8 *pPacket; r = ReadSteamController(device->dev, data, sizeof(data)); - if (r == 0) - { + if (r == 0) { break; } + if (!joystick) { + continue; + } + nPacketLength = 0; if (r > 0) { nPacketLength = WriteSegmentToSteamControllerPacketAssembler(&ctx->m_assembler, data, r); @@ -1281,17 +1264,7 @@ HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device *device) static void HIDAPI_DriverSteam_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - SDL_LockMutex(device->dev_lock); - { - CloseSteamController(device->dev); - - SDL_hid_close(device->dev); - device->dev = NULL; - - SDL_free(device->context); - device->context = NULL; - } - SDL_UnlockMutex(device->dev_lock); + CloseSteamController(device->dev); } static void @@ -1307,7 +1280,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteam = HIDAPI_DriverSteam_UnregisterHints, HIDAPI_DriverSteam_IsEnabled, HIDAPI_DriverSteam_IsSupportedDevice, - HIDAPI_DriverSteam_GetDeviceName, HIDAPI_DriverSteam_InitDevice, HIDAPI_DriverSteam_GetDevicePlayerIndex, HIDAPI_DriverSteam_SetDevicePlayerIndex, diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c index 727b59ce1..e05fdc391 100644 --- a/src/joystick/hidapi/SDL_hidapi_switch.c +++ b/src/joystick/hidapi/SDL_hidapi_switch.c @@ -236,6 +236,7 @@ typedef struct typedef struct { SDL_HIDAPI_Device *device; + SDL_Joystick *joystick; SDL_bool m_bInputOnly; SDL_bool m_bUsingBluetooth; SDL_bool m_bIsGameCube; @@ -556,6 +557,29 @@ static SDL_bool WriteRumble(SDL_DriverSwitch_Context *ctx) return WritePacket(ctx, (Uint8 *)&ctx->m_RumblePacket, sizeof(ctx->m_RumblePacket)); } +static ESwitchDeviceInfoControllerType CalculateControllerType(SDL_DriverSwitch_Context *ctx, ESwitchDeviceInfoControllerType eControllerType) +{ + SDL_HIDAPI_Device *device = ctx->device; + + /* The N64 controller reports as a Pro controller over USB */ + if (eControllerType == k_eSwitchDeviceInfoControllerType_ProController && + device->product_id == USB_PRODUCT_NINTENDO_N64_CONTROLLER) { + eControllerType = k_eSwitchDeviceInfoControllerType_N64; + } + + if (eControllerType == k_eSwitchDeviceInfoControllerType_Unknown) { + /* This might be a Joy-Con that's missing from a charging grip slot */ + if (device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP) { + if (device->interface_number == 1) { + eControllerType = k_eSwitchDeviceInfoControllerType_JoyConLeft; + } else { + eControllerType = k_eSwitchDeviceInfoControllerType_JoyConRight; + } + } + } + return eControllerType; +} + static SDL_bool BReadDeviceInfo(SDL_DriverSwitch_Context *ctx) { SwitchSubcommandInputPacket_t *reply = NULL; @@ -566,13 +590,7 @@ static SDL_bool BReadDeviceInfo(SDL_DriverSwitch_Context *ctx) SwitchProprietaryStatusPacket_t *status = (SwitchProprietaryStatusPacket_t *)&ctx->m_rgucReadBuffer[0]; size_t i; - ctx->m_eControllerType = (ESwitchDeviceInfoControllerType)status->ucDeviceType; - - /* The N64 controller reports as a Pro controller over USB */ - if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_ProController && - ctx->device->product_id == USB_PRODUCT_NINTENDO_N64_CONTROLLER) { - ctx->m_eControllerType = k_eSwitchDeviceInfoControllerType_N64; - } + ctx->m_eControllerType = CalculateControllerType(ctx, (ESwitchDeviceInfoControllerType)status->ucDeviceType); for (i = 0; i < sizeof (ctx->m_rgucMACAddress); ++i) ctx->m_rgucMACAddress[i] = status->rgucMACAddress[ sizeof(ctx->m_rgucMACAddress) - i - 1 ]; @@ -584,7 +602,7 @@ static SDL_bool BReadDeviceInfo(SDL_DriverSwitch_Context *ctx) if (WriteSubcommand(ctx, k_eSwitchSubcommandIDs_RequestDeviceInfo, NULL, 0, &reply)) { // Byte 2: Controller ID (1=LJC, 2=RJC, 3=Pro) - ctx->m_eControllerType = (ESwitchDeviceInfoControllerType)reply->deviceInfo.ucDeviceType; + ctx->m_eControllerType = CalculateControllerType(ctx, (ESwitchDeviceInfoControllerType)reply->deviceInfo.ucDeviceType); // Bytes 4-9: MAC address (big-endian) SDL_memcpy(ctx->m_rgucMACAddress, reply->deviceInfo.rgucMACAddress, sizeof(ctx->m_rgucMACAddress)); @@ -909,6 +927,8 @@ static ESwitchDeviceInfoControllerType ReadJoyConControllerType(SDL_HIDAPI_Device *device) { ESwitchDeviceInfoControllerType eControllerType = k_eSwitchDeviceInfoControllerType_Unknown; + const int MAX_ATTEMPTS = 20; + int attempts = 0; /* Create enough of a context to read the controller type from the device */ SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)SDL_calloc(1, sizeof(*ctx)); @@ -917,39 +937,26 @@ ReadJoyConControllerType(SDL_HIDAPI_Device *device) ctx->m_bSyncWrite = SDL_TRUE; ctx->m_nMaxWriteAttempts = GetMaxWriteAttempts(device); - device->dev = SDL_hid_open_path(device->path, 0); - if (device->dev) { - const int MAX_ATTEMPTS = 20; - int attempts = 0; - for (attempts = 0; attempts < MAX_ATTEMPTS; ++attempts) { - if (WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Status, NULL, 0, SDL_TRUE)) { - SwitchProprietaryStatusPacket_t *status = (SwitchProprietaryStatusPacket_t *)&ctx->m_rgucReadBuffer[0]; + for (attempts = 0; attempts < MAX_ATTEMPTS; ++attempts) { + if (WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Status, NULL, 0, SDL_TRUE)) { + SwitchProprietaryStatusPacket_t *status = (SwitchProprietaryStatusPacket_t *)&ctx->m_rgucReadBuffer[0]; - eControllerType = (ESwitchDeviceInfoControllerType) status->ucDeviceType; + eControllerType = CalculateControllerType(ctx, (ESwitchDeviceInfoControllerType)status->ucDeviceType); + } else { + SwitchSubcommandInputPacket_t *reply = NULL; - /* The N64 controller reports as a Pro controller over USB */ - if (eControllerType == k_eSwitchDeviceInfoControllerType_ProController && - device->product_id == USB_PRODUCT_NINTENDO_N64_CONTROLLER) { - eControllerType = k_eSwitchDeviceInfoControllerType_N64; - } - } else { - SwitchSubcommandInputPacket_t *reply = NULL; - - ctx->m_bUsingBluetooth = SDL_TRUE; - if (WriteSubcommand(ctx, k_eSwitchSubcommandIDs_RequestDeviceInfo, NULL, 0, &reply)) { - eControllerType = (ESwitchDeviceInfoControllerType)reply->deviceInfo.ucDeviceType; - } - } - if (eControllerType == k_eSwitchDeviceInfoControllerType_Unknown) { - /* Wait a bit and try again */ - SDL_Delay(100); - continue; - } else { - break; + ctx->m_bUsingBluetooth = SDL_TRUE; + if (WriteSubcommand(ctx, k_eSwitchSubcommandIDs_RequestDeviceInfo, NULL, 0, &reply)) { + eControllerType = CalculateControllerType(ctx, (ESwitchDeviceInfoControllerType)reply->deviceInfo.ucDeviceType); } } - SDL_hid_close(device->dev); - device->dev = NULL; + if (eControllerType == k_eSwitchDeviceInfoControllerType_Unknown) { + /* Wait a bit and try again */ + SDL_Delay(100); + continue; + } else { + break; + } } SDL_free(ctx); } @@ -1144,121 +1151,91 @@ HIDAPI_DriverSwitch_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *nam return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) ? SDL_TRUE : SDL_FALSE; } -static const char * -HIDAPI_DriverSwitch_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id) -{ - /* Give a user friendly name for this controller */ - if (vendor_id == USB_VENDOR_NINTENDO) { - if (product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP) { - /* We don't know if this is left or right, just leave it alone */ - return NULL; - } - - if (product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT) { - return "Nintendo Switch Joy-Con (L)"; - } - - if (product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT) { - if (SDL_strncmp(name, "NES Controller", 14) == 0) { - if (SDL_strstr(name, "(L)") != 0) { - return "Nintendo NES Controller (L)"; - } else if (SDL_strstr(name, "(R)") != 0) { - return "Nintendo NES Controller (R)"; - } else { - /* Not sure what this is, just leave it alone */ - return NULL; - } - } - return "Nintendo Switch Joy-Con (R)"; - } - - if (product_id == USB_PRODUCT_NINTENDO_N64_CONTROLLER) { - return "Nintendo N64 Controller"; - } - - if (product_id == USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER) { - return "Nintendo SEGA Genesis Controller"; - } - - if (product_id == USB_PRODUCT_NINTENDO_SNES_CONTROLLER) { - return "Nintendo SNES Controller"; - } - } - - return "Nintendo Switch Pro Controller"; -} - static void UpdateDeviceIdentity(SDL_HIDAPI_Device *device) { - ESwitchDeviceInfoControllerType eControllerType = (ESwitchDeviceInfoControllerType)device->guid.data[15]; - const char *name = NULL; + SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context; + char serial[18]; - switch (eControllerType) { + switch (ctx->m_eControllerType) { case k_eSwitchDeviceInfoControllerType_JoyConLeft: - name = "Nintendo Switch Joy-Con (L)"; - SDL_SetJoystickGUIDProduct(&device->guid, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT); + HIDAPI_SetDeviceName(device, "Nintendo Switch Joy-Con (L)"); + HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT); break; case k_eSwitchDeviceInfoControllerType_JoyConRight: - name = "Nintendo Switch Joy-Con (R)"; - SDL_SetJoystickGUIDProduct(&device->guid, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT); + HIDAPI_SetDeviceName(device, "Nintendo Switch Joy-Con (R)"); + HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT); break; case k_eSwitchDeviceInfoControllerType_ProController: - name = "Nintendo Switch Pro Controller"; - SDL_SetJoystickGUIDProduct(&device->guid, USB_PRODUCT_NINTENDO_SWITCH_PRO); + HIDAPI_SetDeviceName(device, "Nintendo Switch Pro Controller"); + HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_SWITCH_PRO); break; case k_eSwitchDeviceInfoControllerType_NESLeft: - name = "Nintendo NES Controller (L)"; + HIDAPI_SetDeviceName(device, "Nintendo NES Controller (L)"); break; case k_eSwitchDeviceInfoControllerType_NESRight: - name = "Nintendo NES Controller (R)"; + HIDAPI_SetDeviceName(device, "Nintendo NES Controller (R)"); break; case k_eSwitchDeviceInfoControllerType_SNES: - name = "Nintendo SNES Controller"; - SDL_SetJoystickGUIDProduct(&device->guid, USB_PRODUCT_NINTENDO_SNES_CONTROLLER); + HIDAPI_SetDeviceName(device, "Nintendo SNES Controller"); + HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_SNES_CONTROLLER); break; case k_eSwitchDeviceInfoControllerType_N64: - name = "Nintendo N64 Controller"; - device->product_id = USB_PRODUCT_NINTENDO_N64_CONTROLLER; + HIDAPI_SetDeviceName(device, "Nintendo N64 Controller"); + HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_N64_CONTROLLER); break; case k_eSwitchDeviceInfoControllerType_SEGA_Genesis: - name = "Nintendo SEGA Genesis Controller"; - SDL_SetJoystickGUIDProduct(&device->guid, USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER); + HIDAPI_SetDeviceName(device, "Nintendo SEGA Genesis Controller"); + HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER); break; default: break; } + device->guid.data[15] = ctx->m_eControllerType; - if (name && (!name || SDL_strcmp(name, device->name) != 0)) { - SDL_free(device->name); - device->name = SDL_strdup(name); - SDL_SetJoystickGUIDCRC(&device->guid, SDL_crc16(0, name, SDL_strlen(name))); - } + SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", + ctx->m_rgucMACAddress[0], + ctx->m_rgucMACAddress[1], + ctx->m_rgucMACAddress[2], + ctx->m_rgucMACAddress[3], + ctx->m_rgucMACAddress[4], + ctx->m_rgucMACAddress[5]); + HIDAPI_SetDeviceSerial(device, serial); } static SDL_bool HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *device) { - /* The NES controllers need additional fix up, since we can't detect them without opening the device */ - if (device->vendor_id == USB_VENDOR_NINTENDO) { - ESwitchDeviceInfoControllerType eControllerType = ReadJoyConControllerType(device); - switch (eControllerType) { - case k_eSwitchDeviceInfoControllerType_Unknown: - /* This might be a Joy-Con that's missing from a charging grip slot */ - if (device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP) { - if (device->interface_number == 1) { - device->guid.data[15] = k_eSwitchDeviceInfoControllerType_JoyConLeft; - } else { - device->guid.data[15] = k_eSwitchDeviceInfoControllerType_JoyConRight; - } - } - break; - default: - device->guid.data[15] = eControllerType; - break; + SDL_DriverSwitch_Context *ctx; + + ctx = (SDL_DriverSwitch_Context *)SDL_calloc(1, sizeof(*ctx)); + if (!ctx) { + SDL_OutOfMemory(); + return SDL_FALSE; + } + ctx->device = device; + device->context = ctx; + + ctx->m_nMaxWriteAttempts = GetMaxWriteAttempts(device); + ctx->m_bSyncWrite = SDL_TRUE; + + if (IsGameCubeFormFactor(device->vendor_id, device->product_id)) { + /* This is a controller shaped like a GameCube controller, with a large central A button */ + ctx->m_bIsGameCube = SDL_TRUE; + } + + /* Find out whether or not we can send output reports */ + ctx->m_bInputOnly = SDL_IsJoystickNintendoSwitchProInputOnly(device->vendor_id, device->product_id); + if (!ctx->m_bInputOnly) { + if (!BReadDeviceInfo(ctx)) { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + "HIDAPI_DriverSwitch_InitDevice(): Couldn't read device info"); + return SDL_FALSE; } + UpdateDeviceIdentity(device); } + return HIDAPI_JoystickConnected(device, NULL); } @@ -1273,7 +1250,7 @@ HIDAPI_DriverSwitch_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystick { SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context; - if (!ctx) { + if (!ctx->joystick) { return; } @@ -1285,41 +1262,22 @@ HIDAPI_DriverSwitch_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystick static SDL_bool HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - SDL_DriverSwitch_Context *ctx; + SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context; Uint8 input_mode; - ctx = (SDL_DriverSwitch_Context *)SDL_calloc(1, sizeof(*ctx)); - if (!ctx) { - SDL_OutOfMemory(); - goto error; - } - ctx->device = device; - device->context = ctx; + ctx->joystick = joystick; - device->dev = SDL_hid_open_path(device->path, 0); - if (!device->dev) { - SDL_SetError("Couldn't open %s", device->path); - goto error; - } - ctx->m_nMaxWriteAttempts = GetMaxWriteAttempts(device); ctx->m_bSyncWrite = SDL_TRUE; - /* Find out whether or not we can send output reports */ - ctx->m_bInputOnly = SDL_IsJoystickNintendoSwitchProInputOnly(device->vendor_id, device->product_id); if (!ctx->m_bInputOnly) { /* Initialize rumble data */ SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]); SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]); - if (!BReadDeviceInfo(ctx)) { - SDL_SetError("Couldn't read device info"); - goto error; - } - if (!ctx->m_bUsingBluetooth) { if (!BTrySetupUSB(ctx)) { SDL_SetError("Couldn't setup USB mode"); - goto error; + return SDL_FALSE; } } @@ -1365,23 +1323,23 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti if (!LoadStickCalibration(ctx, input_mode)) { SDL_SetError("Couldn't load stick calibration"); - goto error; + return SDL_FALSE; } if (!LoadIMUCalibration(ctx)) { SDL_SetError("Couldn't load sensor calibration"); - goto error; + return SDL_FALSE; } if (!SetVibrationEnabled(ctx, 1)) { SDL_SetError("Couldn't enable vibration"); - goto error; + return SDL_FALSE; } /* Set desired input mode */ if (!SetInputMode(ctx, input_mode)) { SDL_SetError("Couldn't set input mode"); - goto error; + return SDL_FALSE; } /* Start sending USB reports */ @@ -1389,7 +1347,7 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti /* ForceUSB doesn't generate an ACK, so don't wait for a reply */ if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_ForceUSB, NULL, 0, SDL_FALSE)) { SDL_SetError("Couldn't start USB reports"); - goto error; + return SDL_FALSE; } } @@ -1404,28 +1362,6 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti SDL_HomeLEDHintChanged, ctx); } } - - /* Set the serial number */ - { - char serial[18]; - - SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", - ctx->m_rgucMACAddress[0], - ctx->m_rgucMACAddress[1], - ctx->m_rgucMACAddress[2], - ctx->m_rgucMACAddress[3], - ctx->m_rgucMACAddress[4], - ctx->m_rgucMACAddress[5]); - if (joystick->serial) { - SDL_free(joystick->serial); - } - joystick->serial = SDL_strdup(serial); - } - } - - if (IsGameCubeFormFactor(device->vendor_id, device->product_id)) { - /* This is a controller shaped like a GameCube controller, with a large central A button */ - ctx->m_bIsGameCube = SDL_TRUE; } if (AlwaysUsesLabels(device->vendor_id, device->product_id, ctx->m_eControllerType)) { @@ -1453,21 +1389,6 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti ctx->m_unLastIMUReset = ctx->m_unLastInput = SDL_GetTicks(); return SDL_TRUE; - -error: - SDL_LockMutex(device->dev_lock); - { - if (device->dev) { - SDL_hid_close(device->dev); - device->dev = NULL; - } - if (device->context) { - SDL_free(device->context); - device->context = NULL; - } - } - SDL_UnlockMutex(device->dev_lock); - return SDL_FALSE; } static int @@ -2142,8 +2063,7 @@ HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device) if (device->num_joysticks > 0) { joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); - } - if (!joystick) { + } else { return SDL_FALSE; } @@ -2153,35 +2073,39 @@ HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device) #ifdef DEBUG_SWITCH_PROTOCOL HIDAPI_DumpPacket("Nintendo Switch packet: size = %d", ctx->m_rgucReadBuffer, size); #endif - if (ctx->m_bInputOnly) { - HandleInputOnlyControllerState(joystick, ctx, (SwitchInputOnlyControllerStatePacket_t *)&ctx->m_rgucReadBuffer[0]); - } else { - switch (ctx->m_rgucReadBuffer[0]) { - case k_eSwitchInputReportIDs_SimpleControllerState: - HandleSimpleControllerState(joystick, ctx, (SwitchSimpleStatePacket_t *)&ctx->m_rgucReadBuffer[1]); - break; - case k_eSwitchInputReportIDs_FullControllerState: - HandleFullControllerState(joystick, ctx, (SwitchStatePacket_t *)&ctx->m_rgucReadBuffer[1]); - break; - default: - break; + if (joystick) { + if (ctx->m_bInputOnly) { + HandleInputOnlyControllerState(joystick, ctx, (SwitchInputOnlyControllerStatePacket_t *)&ctx->m_rgucReadBuffer[0]); + } else { + switch (ctx->m_rgucReadBuffer[0]) { + case k_eSwitchInputReportIDs_SimpleControllerState: + HandleSimpleControllerState(joystick, ctx, (SwitchSimpleStatePacket_t *)&ctx->m_rgucReadBuffer[1]); + break; + case k_eSwitchInputReportIDs_FullControllerState: + HandleFullControllerState(joystick, ctx, (SwitchStatePacket_t *)&ctx->m_rgucReadBuffer[1]); + break; + default: + break; + } } } ctx->m_unLastInput = now; } - if (!ctx->m_bInputOnly && !ctx->m_bUsingBluetooth && - ctx->device->product_id != USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP) { - const Uint32 INPUT_WAIT_TIMEOUT_MS = 100; - if (SDL_TICKS_PASSED(now, ctx->m_unLastInput + INPUT_WAIT_TIMEOUT_MS)) { - /* Steam may have put the controller back into non-reporting mode */ - WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_ForceUSB, NULL, 0, SDL_FALSE); - } - } else if (ctx->m_bUsingBluetooth) { - const Uint32 INPUT_WAIT_TIMEOUT_MS = 3000; - if (SDL_TICKS_PASSED(now, ctx->m_unLastInput + INPUT_WAIT_TIMEOUT_MS)) { - /* Bluetooth may have disconnected, try reopening the controller */ - size = -1; + if (joystick) { + if (!ctx->m_bInputOnly && !ctx->m_bUsingBluetooth && + ctx->device->product_id != USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP) { + const Uint32 INPUT_WAIT_TIMEOUT_MS = 100; + if (SDL_TICKS_PASSED(now, ctx->m_unLastInput + INPUT_WAIT_TIMEOUT_MS)) { + /* Steam may have put the controller back into non-reporting mode */ + WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_ForceUSB, NULL, 0, SDL_FALSE); + } + } else if (ctx->m_bUsingBluetooth) { + const Uint32 INPUT_WAIT_TIMEOUT_MS = 3000; + if (SDL_TICKS_PASSED(now, ctx->m_unLastInput + INPUT_WAIT_TIMEOUT_MS)) { + /* Bluetooth may have disconnected, try reopening the controller */ + size = -1; + } } } @@ -2197,7 +2121,7 @@ HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device) if (size < 0) { /* Read error, device is disconnected */ - HIDAPI_JoystickDisconnected(device, joystick->instance_id); + HIDAPI_JoystickDisconnected(device, device->joysticks[0]); } return (size >= 0); } @@ -2227,15 +2151,7 @@ HIDAPI_DriverSwitch_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, SDL_PlayerLEDHintChanged, ctx); - SDL_LockMutex(device->dev_lock); - { - SDL_hid_close(device->dev); - device->dev = NULL; - - SDL_free(device->context); - device->context = NULL; - } - SDL_UnlockMutex(device->dev_lock); + ctx->joystick = NULL; } static void @@ -2251,7 +2167,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverNintendoClassic = HIDAPI_DriverNintendoClassic_UnregisterHints, HIDAPI_DriverNintendoClassic_IsEnabled, HIDAPI_DriverNintendoClassic_IsSupportedDevice, - HIDAPI_DriverSwitch_GetDeviceName, HIDAPI_DriverSwitch_InitDevice, HIDAPI_DriverSwitch_GetDevicePlayerIndex, HIDAPI_DriverSwitch_SetDevicePlayerIndex, @@ -2275,7 +2190,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverJoyCons = HIDAPI_DriverJoyCons_UnregisterHints, HIDAPI_DriverJoyCons_IsEnabled, HIDAPI_DriverJoyCons_IsSupportedDevice, - HIDAPI_DriverSwitch_GetDeviceName, HIDAPI_DriverSwitch_InitDevice, HIDAPI_DriverSwitch_GetDevicePlayerIndex, HIDAPI_DriverSwitch_SetDevicePlayerIndex, @@ -2299,7 +2213,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch = HIDAPI_DriverSwitch_UnregisterHints, HIDAPI_DriverSwitch_IsEnabled, HIDAPI_DriverSwitch_IsSupportedDevice, - HIDAPI_DriverSwitch_GetDeviceName, HIDAPI_DriverSwitch_InitDevice, HIDAPI_DriverSwitch_GetDevicePlayerIndex, HIDAPI_DriverSwitch_SetDevicePlayerIndex, diff --git a/src/joystick/hidapi/SDL_hidapi_wii.c b/src/joystick/hidapi/SDL_hidapi_wii.c index f7a8eb832..9c9695080 100644 --- a/src/joystick/hidapi/SDL_hidapi_wii.c +++ b/src/joystick/hidapi/SDL_hidapi_wii.c @@ -131,6 +131,7 @@ typedef struct { typedef struct { SDL_HIDAPI_Device *device; + SDL_Joystick *joystick; EWiiCommunicationState m_eCommState; EWiiExtensionControllerType m_eExtensionControllerType; SDL_bool m_bUseButtonLabels; @@ -185,12 +186,6 @@ HIDAPI_DriverWii_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, return SDL_FALSE; } -static const char * -HIDAPI_DriverWii_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id) -{ - return NULL; -} - static int ReadInput(SDL_DriverWii_Context *ctx) { int size; @@ -671,45 +666,35 @@ static void SDLCALL SDL_PlayerLEDHintChanged(void *userdata, const char *name, c static EWiiExtensionControllerType ReadExtensionControllerType(SDL_HIDAPI_Device *device) { + SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)device->context; EWiiExtensionControllerType eExtensionControllerType = k_eWiiExtensionControllerType_Unknown; + const int MAX_ATTEMPTS = 20; + int attempts = 0; /* Create enough of a context to read the controller type from the device */ - SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)SDL_calloc(1, sizeof(*ctx)); - if (ctx) { - ctx->device = device; - - device->dev = SDL_hid_open_path(device->path, 0); - if (device->dev) { - const int MAX_ATTEMPTS = 20; - int attempts = 0; - for (attempts = 0; attempts < MAX_ATTEMPTS; ++attempts) { - Uint16 extension; - if (SendExtensionIdentify(ctx, SDL_TRUE) && - ParseExtensionIdentifyResponse(ctx, &extension)) { - Uint8 motion_plus_mode = 0; - if ((extension & WII_EXTENSION_MOTIONPLUS_MASK) == WII_EXTENSION_MOTIONPLUS_ID) { - motion_plus_mode = (Uint8)(extension >> 8); - } - if (motion_plus_mode || extension == WII_EXTENSION_UNINITIALIZED) { - SendExtensionReset(ctx, SDL_TRUE); - if (SendExtensionIdentify(ctx, SDL_TRUE)) { - ParseExtensionIdentifyResponse(ctx, &extension); - } - } - - eExtensionControllerType = GetExtensionType(extension); - - /* Reset the Motion Plus controller if needed */ - if (motion_plus_mode) { - ActivateMotionPlusWithMode(ctx, motion_plus_mode); - } - break; + for (attempts = 0; attempts < MAX_ATTEMPTS; ++attempts) { + Uint16 extension; + if (SendExtensionIdentify(ctx, SDL_TRUE) && + ParseExtensionIdentifyResponse(ctx, &extension)) { + Uint8 motion_plus_mode = 0; + if ((extension & WII_EXTENSION_MOTIONPLUS_MASK) == WII_EXTENSION_MOTIONPLUS_ID) { + motion_plus_mode = (Uint8)(extension >> 8); + } + if (motion_plus_mode || extension == WII_EXTENSION_UNINITIALIZED) { + SendExtensionReset(ctx, SDL_TRUE); + if (SendExtensionIdentify(ctx, SDL_TRUE)) { + ParseExtensionIdentifyResponse(ctx, &extension); } } - SDL_hid_close(device->dev); - device->dev = NULL; + + eExtensionControllerType = GetExtensionType(extension); + + /* Reset the Motion Plus controller if needed */ + if (motion_plus_mode) { + ActivateMotionPlusWithMode(ctx, motion_plus_mode); + } + break; } - SDL_free(ctx); } return eExtensionControllerType; } @@ -717,41 +702,44 @@ ReadExtensionControllerType(SDL_HIDAPI_Device *device) static void UpdateDeviceIdentity(SDL_HIDAPI_Device *device) { - EWiiExtensionControllerType eExtensionControllerType = (EWiiExtensionControllerType)device->guid.data[15]; - const char *name = NULL; + SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)device->context; - switch (eExtensionControllerType) { - case k_eWiiExtensionControllerType_None: - name = "Nintendo Wii Remote"; - break; - case k_eWiiExtensionControllerType_Nunchuk: - name = "Nintendo Wii Remote with Nunchuk"; - break; - case k_eWiiExtensionControllerType_Gamepad: - name = "Nintendo Wii Remote with Classic Controller"; - break; - case k_eWiiExtensionControllerType_WiiUPro: - name = "Nintendo Wii U Pro Controller"; - break; - default: - name = "Nintendo Wii Remote with Unknown Extension"; - break; - } - if (name && (!name || SDL_strcmp(name, device->name) != 0)) { - SDL_free(device->name); - device->name = SDL_strdup(name); - SDL_SetJoystickGUIDCRC(&device->guid, SDL_crc16(0, name, SDL_strlen(name))); + switch (ctx->m_eExtensionControllerType) { + case k_eWiiExtensionControllerType_None: + HIDAPI_SetDeviceName(device, "Nintendo Wii Remote"); + break; + case k_eWiiExtensionControllerType_Nunchuk: + HIDAPI_SetDeviceName(device, "Nintendo Wii Remote with Nunchuk"); + break; + case k_eWiiExtensionControllerType_Gamepad: + HIDAPI_SetDeviceName(device, "Nintendo Wii Remote with Classic Controller"); + break; + case k_eWiiExtensionControllerType_WiiUPro: + HIDAPI_SetDeviceName(device, "Nintendo Wii U Pro Controller"); + break; + default: + HIDAPI_SetDeviceName(device, "Nintendo Wii Remote with Unknown Extension"); + break; } + device->guid.data[15] = ctx->m_eExtensionControllerType; } static SDL_bool HIDAPI_DriverWii_InitDevice(SDL_HIDAPI_Device *device) { - if (device->vendor_id == USB_VENDOR_NINTENDO) { - EWiiExtensionControllerType eExtensionControllerType; + SDL_DriverWii_Context *ctx; + + ctx = (SDL_DriverWii_Context *)SDL_calloc(1, sizeof(*ctx)); + if (!ctx) { + SDL_OutOfMemory(); + return SDL_FALSE; + } + ctx->device = device; + device->context = ctx; + + if (device->vendor_id == USB_VENDOR_NINTENDO) { + ctx->m_eExtensionControllerType = ReadExtensionControllerType(device); - eExtensionControllerType = ReadExtensionControllerType(device); - device->guid.data[15] = eExtensionControllerType; UpdateDeviceIdentity(device); } return HIDAPI_JoystickConnected(device, NULL); @@ -766,9 +754,9 @@ HIDAPI_DriverWii_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID static void HIDAPI_DriverWii_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) { - SDL_DriverWii_Context *ctx = device->context; + SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)device->context; - if (!ctx) { + if (!ctx->joystick) { return; } @@ -780,23 +768,9 @@ HIDAPI_DriverWii_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID static SDL_bool HIDAPI_DriverWii_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - SDL_DriverWii_Context *ctx; + SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)device->context; - ctx = (SDL_DriverWii_Context *)SDL_calloc(1, sizeof(*ctx)); - if (!ctx) { - SDL_OutOfMemory(); - goto error; - } - ctx->device = device; - device->context = ctx; - - device->dev = SDL_hid_open_path(device->path, 0); - if (!device->dev) { - SDL_SetError("Couldn't open %s", device->path); - goto error; - } - - ctx->m_eExtensionControllerType = (EWiiExtensionControllerType)device->guid.data[15]; + ctx->joystick = joystick; InitializeExtension(ctx); @@ -841,21 +815,6 @@ HIDAPI_DriverWii_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) ctx->m_unLastInput = SDL_GetTicks(); return SDL_TRUE; - -error: - SDL_LockMutex(device->dev_lock); - { - if (device->dev) { - SDL_hid_close(device->dev); - device->dev = NULL; - } - if (device->context) { - SDL_free(device->context); - device->context = NULL; - } - } - SDL_UnlockMutex(device->dev_lock); - return SDL_FALSE; } static int @@ -1509,16 +1468,16 @@ HIDAPI_DriverWii_UpdateDevice(SDL_HIDAPI_Device *device) if (device->num_joysticks > 0) { joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); - } - if (!joystick) { + } else { return SDL_FALSE; } now = SDL_GetTicks(); while ((size = ReadInput(ctx)) > 0) { - HandleInput(ctx, joystick); - + if (joystick) { + HandleInput(ctx, joystick); + } ctx->m_unLastInput = now; } @@ -1533,36 +1492,38 @@ HIDAPI_DriverWii_UpdateDevice(SDL_HIDAPI_Device *device) size = -1; } - /* These checks aren't needed on the Wii U Pro Controller */ - if (ctx->m_eExtensionControllerType != k_eWiiExtensionControllerType_WiiUPro) { + if (joystick) { + /* These checks aren't needed on the Wii U Pro Controller */ + if (ctx->m_eExtensionControllerType != k_eWiiExtensionControllerType_WiiUPro) { - /* Check to see if the Motion Plus extension status has changed */ - if (ctx->m_unNextMotionPlusCheck && - SDL_TICKS_PASSED(now, ctx->m_unNextMotionPlusCheck)) { - CheckMotionPlusConnection(ctx); - if (NeedsPeriodicMotionPlusCheck(ctx, SDL_FALSE)) { - SchedulePeriodicMotionPlusCheck(ctx); - } else { - ctx->m_unNextMotionPlusCheck = 0; + /* Check to see if the Motion Plus extension status has changed */ + if (ctx->m_unNextMotionPlusCheck && + SDL_TICKS_PASSED(now, ctx->m_unNextMotionPlusCheck)) { + CheckMotionPlusConnection(ctx); + if (NeedsPeriodicMotionPlusCheck(ctx, SDL_FALSE)) { + SchedulePeriodicMotionPlusCheck(ctx); + } else { + ctx->m_unNextMotionPlusCheck = 0; + } } - } - /* Request a status update periodically to make sure our battery value is up to date */ - if (!ctx->m_unLastStatus || - SDL_TICKS_PASSED(now, ctx->m_unLastStatus + STATUS_UPDATE_TIME_MS)) { - Uint8 data[2]; + /* Request a status update periodically to make sure our battery value is up to date */ + if (!ctx->m_unLastStatus || + SDL_TICKS_PASSED(now, ctx->m_unLastStatus + STATUS_UPDATE_TIME_MS)) { + Uint8 data[2]; - data[0] = k_eWiiOutputReportIDs_StatusRequest; - data[1] = ctx->m_bRumbleActive; - WriteOutput(ctx, data, sizeof(data), SDL_FALSE); + data[0] = k_eWiiOutputReportIDs_StatusRequest; + data[1] = ctx->m_bRumbleActive; + WriteOutput(ctx, data, sizeof(data), SDL_FALSE); - ctx->m_unLastStatus = now; + ctx->m_unLastStatus = now; + } } } if (size < 0 || ctx->m_bDisconnected) { /* Read error, device is disconnected */ - HIDAPI_JoystickDisconnected(device, joystick->instance_id); + HIDAPI_JoystickDisconnected(device, device->joysticks[0]); } return (size >= 0); } @@ -1578,15 +1539,7 @@ HIDAPI_DriverWii_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_WII_PLAYER_LED, SDL_PlayerLEDHintChanged, ctx); - SDL_LockMutex(device->dev_lock); - { - SDL_hid_close(device->dev); - device->dev = NULL; - - SDL_free(device->context); - device->context = NULL; - } - SDL_UnlockMutex(device->dev_lock); + ctx->joystick = NULL; } static void @@ -1602,7 +1555,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverWii = HIDAPI_DriverWii_UnregisterHints, HIDAPI_DriverWii_IsEnabled, HIDAPI_DriverWii_IsSupportedDevice, - HIDAPI_DriverWii_GetDeviceName, HIDAPI_DriverWii_InitDevice, HIDAPI_DriverWii_GetDevicePlayerIndex, HIDAPI_DriverWii_SetDevicePlayerIndex, diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360.c b/src/joystick/hidapi/SDL_hidapi_xbox360.c index 5254a16ad..a73071b94 100644 --- a/src/joystick/hidapi/SDL_hidapi_xbox360.c +++ b/src/joystick/hidapi/SDL_hidapi_xbox360.c @@ -40,6 +40,7 @@ typedef struct { SDL_HIDAPI_Device *device; + SDL_Joystick *joystick; int player_index; SDL_bool player_lights; Uint8 last_state[USB_PACKET_LENGTH]; @@ -108,12 +109,6 @@ HIDAPI_DriverXbox360_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *na #endif } -static const char * -HIDAPI_DriverXbox360_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id) -{ - return NULL; -} - static SDL_bool SetSlotLED(SDL_hid_device *dev, Uint8 slot, SDL_bool on) { const SDL_bool blink = SDL_FALSE; @@ -151,6 +146,17 @@ static void SDLCALL SDL_PlayerLEDHintChanged(void *userdata, const char *name, c static SDL_bool HIDAPI_DriverXbox360_InitDevice(SDL_HIDAPI_Device *device) { + SDL_DriverXbox360_Context *ctx; + + ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx)); + if (!ctx) { + SDL_OutOfMemory(); + return SDL_FALSE; + } + ctx->device = device; + + device->context = ctx; + return HIDAPI_JoystickConnected(device, NULL); } @@ -165,7 +171,7 @@ HIDAPI_DriverXbox360_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystic { SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context; - if (!ctx) { + if (!ctx->joystick) { return; } @@ -177,22 +183,10 @@ HIDAPI_DriverXbox360_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystic static SDL_bool HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - SDL_DriverXbox360_Context *ctx; + SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context; - ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx)); - if (!ctx) { - SDL_OutOfMemory(); - return SDL_FALSE; - } - ctx->device = device; - - device->dev = SDL_hid_open_path(device->path, 0); - if (!device->dev) { - SDL_SetError("Couldn't open %s", device->path); - SDL_free(ctx); - return SDL_FALSE; - } - device->context = ctx; + ctx->joystick = joystick; + SDL_zeroa(ctx->last_state); /* Initialize player index (needed for setting LEDs) */ ctx->player_index = SDL_JoystickGetPlayerIndex(joystick); @@ -343,8 +337,7 @@ HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device) if (device->num_joysticks > 0) { joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); - } - if (!joystick) { + } else { return SDL_FALSE; } @@ -352,6 +345,10 @@ HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device) #ifdef DEBUG_XBOX_PROTOCOL HIDAPI_DumpPacket("Xbox 360 packet: size = %d", data, size); #endif + if (!joystick) { + continue; + } + if (data[0] == 0x00) { HIDAPI_DriverXbox360_HandleStatePacket(joystick, ctx, data, size); } @@ -359,7 +356,7 @@ HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device) if (size < 0) { /* Read error, device is disconnected */ - HIDAPI_JoystickDisconnected(device, joystick->instance_id); + HIDAPI_JoystickDisconnected(device, device->joysticks[0]); } return (size >= 0); } @@ -372,17 +369,7 @@ HIDAPI_DriverXbox360_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joys SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED, SDL_PlayerLEDHintChanged, ctx); - SDL_LockMutex(device->dev_lock); - { - if (device->dev) { - SDL_hid_close(device->dev); - device->dev = NULL; - } - - SDL_free(device->context); - device->context = NULL; - } - SDL_UnlockMutex(device->dev_lock); + ctx->joystick = NULL; } static void @@ -398,7 +385,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 = HIDAPI_DriverXbox360_UnregisterHints, HIDAPI_DriverXbox360_IsEnabled, HIDAPI_DriverXbox360_IsSupportedDevice, - HIDAPI_DriverXbox360_GetDeviceName, HIDAPI_DriverXbox360_InitDevice, HIDAPI_DriverXbox360_GetDevicePlayerIndex, HIDAPI_DriverXbox360_SetDevicePlayerIndex, diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360w.c b/src/joystick/hidapi/SDL_hidapi_xbox360w.c index c3fd3a010..5869aff49 100644 --- a/src/joystick/hidapi/SDL_hidapi_xbox360w.c +++ b/src/joystick/hidapi/SDL_hidapi_xbox360w.c @@ -41,7 +41,6 @@ typedef struct { SDL_HIDAPI_Device *device; SDL_bool connected; - SDL_bool opened; int player_index; SDL_bool player_lights; Uint8 last_state[USB_PACKET_LENGTH]; @@ -86,12 +85,6 @@ HIDAPI_DriverXbox360W_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *n return SDL_FALSE; } -static const char * -HIDAPI_DriverXbox360W_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id) -{ - return "Xbox 360 Wireless Controller"; -} - static SDL_bool SetSlotLED(SDL_hid_device *dev, Uint8 slot, SDL_bool on) { const SDL_bool blink = SDL_FALSE; @@ -150,6 +143,8 @@ HIDAPI_DriverXbox360W_InitDevice(SDL_HIDAPI_Device *device) /* Requests controller presence information from the wireless dongle */ const Uint8 init_packet[] = { 0x08, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + HIDAPI_SetDeviceName(device, "Xbox 360 Wireless Controller"); + ctx = (SDL_DriverXbox360W_Context *)SDL_calloc(1, sizeof(*ctx)); if (!ctx) { SDL_OutOfMemory(); @@ -157,12 +152,6 @@ HIDAPI_DriverXbox360W_InitDevice(SDL_HIDAPI_Device *device) } ctx->device = device; - device->dev = SDL_hid_open_path(device->path, 0); - if (!device->dev) { - SDL_free(ctx); - SDL_SetError("Couldn't open %s", device->path); - return SDL_FALSE; - } device->context = ctx; if (SDL_hid_write(device->dev, init_packet, sizeof(init_packet)) != sizeof(init_packet)) { @@ -200,8 +189,6 @@ HIDAPI_DriverXbox360W_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joys SDL_zeroa(ctx->last_state); - ctx->opened = SDL_TRUE; - /* Initialize player index (needed for setting LEDs) */ ctx->player_index = SDL_JoystickGetPlayerIndex(joystick); ctx->player_lights = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED, SDL_TRUE); @@ -367,11 +354,9 @@ HIDAPI_DriverXbox360W_UpdateDevice(SDL_HIDAPI_Device *device) } } - if (joystick) { - if (size < 0) { - /* Read error, device is disconnected */ - HIDAPI_JoystickDisconnected(device, joystick->instance_id); - } + if (size < 0 && device->num_joysticks > 0) { + /* Read error, device is disconnected */ + HIDAPI_JoystickDisconnected(device, device->joysticks[0]); } return (size >= 0); } @@ -383,22 +368,11 @@ HIDAPI_DriverXbox360W_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED, SDL_PlayerLEDHintChanged, ctx); - - ctx->opened = SDL_FALSE; } static void HIDAPI_DriverXbox360W_FreeDevice(SDL_HIDAPI_Device *device) { - SDL_LockMutex(device->dev_lock); - { - SDL_hid_close(device->dev); - device->dev = NULL; - - SDL_free(device->context); - device->context = NULL; - } - SDL_UnlockMutex(device->dev_lock); } SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W = @@ -409,7 +383,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W = HIDAPI_DriverXbox360W_UnregisterHints, HIDAPI_DriverXbox360W_IsEnabled, HIDAPI_DriverXbox360W_IsSupportedDevice, - HIDAPI_DriverXbox360W_GetDeviceName, HIDAPI_DriverXbox360W_InitDevice, HIDAPI_DriverXbox360W_GetDevicePlayerIndex, HIDAPI_DriverXbox360W_SetDevicePlayerIndex, diff --git a/src/joystick/hidapi/SDL_hidapi_xboxone.c b/src/joystick/hidapi/SDL_hidapi_xboxone.c index 17a30a072..987fb6987 100644 --- a/src/joystick/hidapi/SDL_hidapi_xboxone.c +++ b/src/joystick/hidapi/SDL_hidapi_xboxone.c @@ -106,7 +106,6 @@ typedef struct { Uint32 start_time; Uint8 sequence; Uint32 send_time; - Uint8 last_state[USB_PACKET_LENGTH]; SDL_bool has_guide_packet; SDL_bool has_color_led; SDL_bool has_paddles; @@ -116,6 +115,7 @@ typedef struct { Uint8 high_frequency_rumble; Uint8 left_trigger_rumble; Uint8 right_trigger_rumble; + Uint8 last_state[USB_PACKET_LENGTH]; } SDL_DriverXboxOne_Context; static SDL_bool @@ -306,34 +306,8 @@ HIDAPI_DriverXboxOne_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *na return (type == SDL_CONTROLLER_TYPE_XBOXONE) ? SDL_TRUE : SDL_FALSE; } -static const char * -HIDAPI_DriverXboxOne_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id) -{ - return NULL; -} - static SDL_bool HIDAPI_DriverXboxOne_InitDevice(SDL_HIDAPI_Device *device) -{ - return HIDAPI_JoystickConnected(device, NULL); -} - -static int -HIDAPI_DriverXboxOne_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id) -{ - return -1; -} - -static void -HIDAPI_DriverXboxOne_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) -{ -} - -static SDL_bool HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick); -static void HIDAPI_DriverXboxOne_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick); - -static SDL_bool -HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { SDL_DriverXboxOne_Context *ctx; @@ -343,12 +317,6 @@ HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst return SDL_FALSE; } - device->dev = SDL_hid_open_path(device->path, 0); - if (!device->dev) { - SDL_free(ctx); - SDL_SetError("Couldn't open %s", device->path); - return SDL_FALSE; - } device->context = ctx; ctx->vendor_id = device->vendor_id; @@ -372,6 +340,31 @@ HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst SDL_Log("Controller version: %d (0x%.4x)\n", device->version, device->version); #endif + return HIDAPI_JoystickConnected(device, NULL); +} + +static int +HIDAPI_DriverXboxOne_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id) +{ + return -1; +} + +static void +HIDAPI_DriverXboxOne_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) +{ +} + +static SDL_bool +HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) +{ + SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context; + + ctx->low_frequency_rumble = 0; + ctx->high_frequency_rumble = 0; + ctx->left_trigger_rumble = 0; + ctx->right_trigger_rumble = 0; + SDL_zeroa(ctx->last_state); + /* Initialize the joystick capabilities */ joystick->nbuttons = 15; if (ctx->has_share_button) { @@ -975,12 +968,19 @@ HIDAPI_DriverXboxOne_UpdateInitState(SDL_HIDAPI_Device *device, SDL_DriverXboxOn } static SDL_bool -HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) +HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device) { SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context; + SDL_Joystick *joystick = NULL; Uint8 data[USB_PACKET_LENGTH]; int size; + if (device->num_joysticks > 0) { + joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); + } else { + return SDL_FALSE; + } + while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) { #ifdef DEBUG_XBOX_PROTOCOL HIDAPI_DumpPacket("Xbox One packet: size = %d", data, size); @@ -988,6 +988,9 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy if (ctx->bluetooth) { switch (data[0]) { case 0x01: + if (!joystick) { + break; + } if (size >= 16) { HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(joystick, ctx, data, size); } else { @@ -997,9 +1000,15 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy } break; case 0x02: + if (!joystick) { + break; + } HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(joystick, ctx, data, size); break; case 0x04: + if (!joystick) { + break; + } HIDAPI_DriverXboxOneBluetooth_HandleBatteryPacket(joystick, ctx, data, size); break; default: @@ -1045,6 +1054,10 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy break; case 0x03: /* Controller status update */ + if (!joystick) { + /* We actually want to handle this packet any time it arrives */ + /*break;*/ + } HIDAPI_DriverXboxOne_HandleStatusPacket(joystick, ctx, data, size); break; case 0x04: @@ -1054,6 +1067,9 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy /* Unknown chatty controller information, sent by both sides */ break; case 0x07: + if (!joystick) { + break; + } HIDAPI_DriverXboxOne_HandleModePacket(joystick, ctx, data, size); break; case 0x1E: @@ -1066,6 +1082,9 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy The controller sends that in response to this request: 0x1E 0x30 0x07 0x01 0x04 */ + if (!joystick) { + break; + } #ifdef SET_SERIAL_AFTER_OPEN if (size == 20 && data[3] == 0x10) { HIDAPI_DriverXboxOne_HandleSerialIDPacket(joystick, ctx, data, size); @@ -1082,6 +1101,9 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy #endif break; } + if (!joystick) { + break; + } HIDAPI_DriverXboxOne_HandleStatePacket(joystick, ctx, data, size); break; default: @@ -1111,37 +1133,14 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy if (size < 0) { /* Read error, device is disconnected */ - HIDAPI_JoystickDisconnected(device, joystick->instance_id); + HIDAPI_JoystickDisconnected(device, device->joysticks[0]); } return (size >= 0); } -static SDL_bool -HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device) -{ - SDL_Joystick *joystick = NULL; - - if (device->num_joysticks > 0) { - joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); - } - if (!joystick) { - return SDL_FALSE; - } - return HIDAPI_DriverXboxOne_UpdateJoystick(device, joystick); -} - static void HIDAPI_DriverXboxOne_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - SDL_LockMutex(device->dev_lock); - { - SDL_hid_close(device->dev); - device->dev = NULL; - - SDL_free(device->context); - device->context = NULL; - } - SDL_UnlockMutex(device->dev_lock); } static void @@ -1157,7 +1156,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne = HIDAPI_DriverXboxOne_UnregisterHints, HIDAPI_DriverXboxOne_IsEnabled, HIDAPI_DriverXboxOne_IsSupportedDevice, - HIDAPI_DriverXboxOne_GetDeviceName, HIDAPI_DriverXboxOne_InitDevice, HIDAPI_DriverXboxOne_GetDevicePlayerIndex, HIDAPI_DriverXboxOne_SetDevicePlayerIndex, diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c index 57764de2f..0a3873a71 100644 --- a/src/joystick/hidapi/SDL_hidapijoystick.c +++ b/src/joystick/hidapi/SDL_hidapijoystick.c @@ -314,6 +314,20 @@ HIDAPI_CleanupDeviceDriver(SDL_HIDAPI_Device *device) device->driver->FreeDevice(device); device->driver = NULL; + + SDL_LockMutex(device->dev_lock); + { + if (device->dev) { + SDL_hid_close(device->dev); + device->dev = NULL; + } + + if (device->context) { + SDL_free(device->context); + device->context = NULL; + } + } + SDL_UnlockMutex(device->dev_lock); } static void @@ -344,18 +358,27 @@ HIDAPI_SetupDeviceDriver(SDL_HIDAPI_Device *device) return; /* Already setup */ } - device->driver = HIDAPI_GetDeviceDriver(device); - if (device->driver) { - const char *name = device->driver->GetDeviceName(device->name, device->vendor_id, device->product_id); - if (name && name != device->name) { - SDL_free(device->name); - device->name = SDL_strdup(name); - } + /* Make sure we can open the device and leave it open for the driver */ + device->dev = SDL_hid_open_path(device->path, 0); + if (!device->dev) { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + "HIDAPI_SetupDeviceDriver() couldn't open %s: %s\n", + device->path, SDL_GetError()); + return; } + SDL_hid_set_nonblocking(device->dev, 1); + + device->driver = HIDAPI_GetDeviceDriver(device); /* Initialize the device, which may cause a connected event */ if (device->driver && !device->driver->InitDevice(device)) { - device->driver = NULL; + HIDAPI_CleanupDeviceDriver(device); + } + + if (!device->driver && device->dev) { + /* No driver claimed this device, go ahead and close it */ + SDL_hid_close(device->dev); + device->dev = NULL; } } @@ -481,6 +504,32 @@ HIDAPI_JoystickInstanceIsUnique(SDL_HIDAPI_Device *device, SDL_JoystickID joysti return SDL_TRUE; } +void +HIDAPI_SetDeviceName(SDL_HIDAPI_Device *device, const char *name) +{ + if (name && *name && SDL_strcmp(name, device->name) != 0) { + SDL_free(device->name); + device->name = SDL_strdup(name); + SDL_SetJoystickGUIDCRC(&device->guid, SDL_crc16(0, name, SDL_strlen(name))); + } +} + +void +HIDAPI_SetDeviceProduct(SDL_HIDAPI_Device *device, Uint16 product_id) +{ + /* Don't set the device product ID directly, or we'll constantly re-enumerate this device */ + SDL_SetJoystickGUIDProduct(&device->guid, product_id); +} + +void +HIDAPI_SetDeviceSerial(SDL_HIDAPI_Device *device, const char *serial) +{ + if (serial && *serial && (!device->serial || SDL_strcmp(serial, device->serial) != 0)) { + SDL_free(device->serial); + device->serial = SDL_strdup(serial); + } +} + SDL_bool HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID) { @@ -1102,6 +1151,13 @@ HIDAPI_JoystickOpen(SDL_Joystick *joystick, int device_index) } hwdata->device = device; + /* Process any pending reports before opening the device */ + SDL_LockMutex(device->dev_lock); + device->updating = SDL_TRUE; + device->driver->UpdateDevice(device); + device->updating = SDL_FALSE; + SDL_UnlockMutex(device->dev_lock); + if (!device->driver->OpenJoystick(device, joystick)) { /* The open failed, mark this device as disconnected and update devices */ HIDAPI_JoystickDisconnected(device, joystickID); diff --git a/src/joystick/hidapi/SDL_hidapijoystick_c.h b/src/joystick/hidapi/SDL_hidapijoystick_c.h index 58c35914a..3b574d657 100644 --- a/src/joystick/hidapi/SDL_hidapijoystick_c.h +++ b/src/joystick/hidapi/SDL_hidapijoystick_c.h @@ -103,7 +103,6 @@ typedef struct _SDL_HIDAPI_DeviceDriver void (*UnregisterHints)(SDL_HintCallback callback, void *userdata); SDL_bool (*IsEnabled)(void); SDL_bool (*IsSupportedDevice)(SDL_HIDAPI_Device *device, 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); - const char *(*GetDeviceName)(const char *name, Uint16 vendor_id, Uint16 product_id); SDL_bool (*InitDevice)(SDL_HIDAPI_Device *device); int (*GetDevicePlayerIndex)(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id); void (*SetDevicePlayerIndex)(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index); @@ -146,6 +145,9 @@ extern SDL_bool HIDAPI_IsDeviceTypePresent(SDL_GameControllerType type); extern SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name); extern void HIDAPI_UpdateDevices(void); +extern void HIDAPI_SetDeviceName(SDL_HIDAPI_Device *device, const char *name); +extern void HIDAPI_SetDeviceProduct(SDL_HIDAPI_Device *device, Uint16 product_id); +extern void HIDAPI_SetDeviceSerial(SDL_HIDAPI_Device *device, const char *serial); extern SDL_bool HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID); extern void HIDAPI_JoystickDisconnected(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID);