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.
This commit is contained in:
Sam Lantinga 2022-09-22 18:22:17 -07:00
parent 2857e3c748
commit aa2e2f4843
17 changed files with 811 additions and 1072 deletions

View file

@ -130,7 +130,6 @@ struct hid_device_list_node
static IOHIDManagerRef hid_mgr = 0x0; static IOHIDManagerRef hid_mgr = 0x0;
static struct hid_device_list_node *device_list = 0x0; static struct hid_device_list_node *device_list = 0x0;
static int hid_input_monitoring_denied = 0;
static hid_device *new_hid_device(void) static hid_device *new_hid_device(void)
{ {
@ -523,10 +522,6 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
if (hid_init() < 0) if (hid_init() < 0)
return NULL; 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 */ /* give the IOHIDManager a chance to update itself */
process_pending_events(); process_pending_events();
@ -867,11 +862,6 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive)
return dev; return dev;
} }
else if (ret == kIOReturnNotPermitted) {
/* This application doesn't have input monitoring permissions */
hid_input_monitoring_denied = 1;
goto return_error;
}
else { else {
goto return_error; goto return_error;
} }

View file

@ -52,12 +52,6 @@ HIDAPI_DriverCombined_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *n
return SDL_FALSE; return SDL_FALSE;
} }
static const char *
HIDAPI_DriverCombined_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id)
{
return NULL;
}
static SDL_bool static SDL_bool
HIDAPI_DriverCombined_InitDevice(SDL_HIDAPI_Device *device) HIDAPI_DriverCombined_InitDevice(SDL_HIDAPI_Device *device)
{ {
@ -241,7 +235,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverCombined =
HIDAPI_DriverCombined_UnregisterHints, HIDAPI_DriverCombined_UnregisterHints,
HIDAPI_DriverCombined_IsEnabled, HIDAPI_DriverCombined_IsEnabled,
HIDAPI_DriverCombined_IsSupportedDevice, HIDAPI_DriverCombined_IsSupportedDevice,
HIDAPI_DriverCombined_GetDeviceName,
HIDAPI_DriverCombined_InitDevice, HIDAPI_DriverCombined_InitDevice,
HIDAPI_DriverCombined_GetDevicePlayerIndex, HIDAPI_DriverCombined_GetDevicePlayerIndex,
HIDAPI_DriverCombined_SetDevicePlayerIndex, HIDAPI_DriverCombined_SetDevicePlayerIndex,

View file

@ -89,12 +89,6 @@ HIDAPI_DriverGameCube_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *n
return SDL_FALSE; return SDL_FALSE;
} }
static const char *
HIDAPI_DriverGameCube_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id)
{
return "Nintendo GameCube Controller";
}
static void static void
ResetAxisRange(SDL_DriverGameCube_Context *ctx, int joystick_index) ResetAxisRange(SDL_DriverGameCube_Context *ctx, int joystick_index)
{ {
@ -151,18 +145,13 @@ HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
SDL_EnableGameCubeAdaptors(); SDL_EnableGameCubeAdaptors();
#endif #endif
HIDAPI_SetDeviceName(device, "Nintendo GameCube Controller");
ctx = (SDL_DriverGameCube_Context *)SDL_calloc(1, sizeof(*ctx)); ctx = (SDL_DriverGameCube_Context *)SDL_calloc(1, sizeof(*ctx));
if (!ctx) { if (!ctx) {
SDL_OutOfMemory(); SDL_OutOfMemory();
return SDL_FALSE; 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; device->context = ctx;
ctx->joysticks[0] = -1; ctx->joysticks[0] = -1;
@ -184,8 +173,9 @@ HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
} else { } else {
/* This is all that's needed to initialize the device. Really! */ /* This is all that's needed to initialize the device. Really! */
if (SDL_hid_write(device->dev, &initMagic, sizeof(initMagic)) != sizeof(initMagic)) { if (SDL_hid_write(device->dev, &initMagic, sizeof(initMagic)) != sizeof(initMagic)) {
SDL_SetError("Couldn't initialize WUP-028"); SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
goto error; "HIDAPI_DriverGameCube_InitDevice(): Couldn't initialize WUP-028");
return SDL_FALSE;
} }
/* Wait for the adapter to initialize */ /* Wait for the adapter to initialize */
@ -230,22 +220,6 @@ HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
SDL_GameControllerButtonReportingHintChanged, ctx); SDL_GameControllerButtonReportingHintChanged, ctx);
return SDL_TRUE; 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 static int
@ -565,16 +539,6 @@ HIDAPI_DriverGameCube_FreeDevice(SDL_HIDAPI_Device *device)
SDL_GameControllerButtonReportingHintChanged, ctx); SDL_GameControllerButtonReportingHintChanged, ctx);
SDL_DelHintCallback(SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE, SDL_DelHintCallback(SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE,
SDL_JoystickGameCubeRumbleBrakeHintChanged, ctx); 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 = SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube =
@ -585,7 +549,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube =
HIDAPI_DriverGameCube_UnregisterHints, HIDAPI_DriverGameCube_UnregisterHints,
HIDAPI_DriverGameCube_IsEnabled, HIDAPI_DriverGameCube_IsEnabled,
HIDAPI_DriverGameCube_IsSupportedDevice, HIDAPI_DriverGameCube_IsSupportedDevice,
HIDAPI_DriverGameCube_GetDeviceName,
HIDAPI_DriverGameCube_InitDevice, HIDAPI_DriverGameCube_InitDevice,
HIDAPI_DriverGameCube_GetDevicePlayerIndex, HIDAPI_DriverGameCube_GetDevicePlayerIndex,
HIDAPI_DriverGameCube_SetDevicePlayerIndex, HIDAPI_DriverGameCube_SetDevicePlayerIndex,

View file

@ -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; 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 static SDL_bool
HIDAPI_DriverLuna_InitDevice(SDL_HIDAPI_Device *device) 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); return HIDAPI_JoystickConnected(device, NULL);
} }
@ -98,27 +103,14 @@ HIDAPI_DriverLuna_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID
static SDL_bool static SDL_bool
HIDAPI_DriverLuna_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 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)); SDL_zeroa(ctx->last_state);
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;
/* Initialize the joystick capabilities */ /* Initialize the joystick capabilities */
joystick->nbuttons = SDL_CONTROLLER_NUM_LUNA_BUTTONS; joystick->nbuttons = SDL_CONTROLLER_NUM_LUNA_BUTTONS;
joystick->naxes = SDL_CONTROLLER_AXIS_MAX; joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL; joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
joystick->serial = NULL;
return SDL_TRUE; return SDL_TRUE;
} }
@ -406,8 +398,7 @@ HIDAPI_DriverLuna_UpdateDevice(SDL_HIDAPI_Device *device)
if (device->num_joysticks > 0) { if (device->num_joysticks > 0) {
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
} } else {
if (!joystick) {
return SDL_FALSE; return SDL_FALSE;
} }
@ -415,6 +406,10 @@ HIDAPI_DriverLuna_UpdateDevice(SDL_HIDAPI_Device *device)
#ifdef DEBUG_LUNA_PROTOCOL #ifdef DEBUG_LUNA_PROTOCOL
HIDAPI_DumpPacket("Amazon Luna packet: size = %d", data, size); HIDAPI_DumpPacket("Amazon Luna packet: size = %d", data, size);
#endif #endif
if (!joystick) {
continue;
}
switch (size) { switch (size) {
case 10: case 10:
HIDAPI_DriverLuna_HandleUSBStatePacket(joystick, ctx, data, size); HIDAPI_DriverLuna_HandleUSBStatePacket(joystick, ctx, data, size);
@ -427,7 +422,7 @@ HIDAPI_DriverLuna_UpdateDevice(SDL_HIDAPI_Device *device)
if (size < 0) { if (size < 0) {
/* Read error, device is disconnected */ /* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, joystick->instance_id); HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
} }
return (size >= 0); return (size >= 0);
} }
@ -435,17 +430,6 @@ HIDAPI_DriverLuna_UpdateDevice(SDL_HIDAPI_Device *device)
static void static void
HIDAPI_DriverLuna_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 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 static void
@ -461,7 +445,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverLuna =
HIDAPI_DriverLuna_UnregisterHints, HIDAPI_DriverLuna_UnregisterHints,
HIDAPI_DriverLuna_IsEnabled, HIDAPI_DriverLuna_IsEnabled,
HIDAPI_DriverLuna_IsSupportedDevice, HIDAPI_DriverLuna_IsSupportedDevice,
HIDAPI_DriverLuna_GetDeviceName,
HIDAPI_DriverLuna_InitDevice, HIDAPI_DriverLuna_InitDevice,
HIDAPI_DriverLuna_GetDevicePlayerIndex, HIDAPI_DriverLuna_GetDevicePlayerIndex,
HIDAPI_DriverLuna_SetDevicePlayerIndex, HIDAPI_DriverLuna_SetDevicePlayerIndex,

View file

@ -52,10 +52,10 @@ typedef struct {
SDL_bool is_shanwan; SDL_bool is_shanwan;
SDL_bool report_sensors; SDL_bool report_sensors;
SDL_bool effects_updated; SDL_bool effects_updated;
Uint8 last_state[USB_PACKET_LENGTH];
int player_index; int player_index;
Uint8 rumble_left; Uint8 rumble_left;
Uint8 rumble_right; Uint8 rumble_right;
Uint8 last_state[USB_PACKET_LENGTH];
} SDL_DriverPS3_Context; } SDL_DriverPS3_Context;
@ -76,16 +76,16 @@ HIDAPI_DriverPS3_UnregisterHints(SDL_HintCallback callback, void *userdata)
static SDL_bool static SDL_bool
HIDAPI_DriverPS3_IsEnabled(void) HIDAPI_DriverPS3_IsEnabled(void)
{ {
SDL_bool default_value;
#if defined(__MACOSX__) #if defined(__MACOSX__)
/* This works well on macOS */ /* This works well on macOS */
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3, default_value = SDL_TRUE;
SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
SDL_HIDAPI_DEFAULT));
#elif defined(__WINDOWS__) #elif defined(__WINDOWS__)
/* You can't initialize the controller with the stock Windows drivers /* You can't initialize the controller with the stock Windows drivers
* See https://github.com/ViGEm/DsHidMini as an alternative driver * See https://github.com/ViGEm/DsHidMini as an alternative driver
*/ */
return SDL_FALSE; default_value = SDL_FALSE;
#elif defined(__LINUX__) #elif defined(__LINUX__)
/* Linux drivers do a better job of managing the transition between /* Linux drivers do a better job of managing the transition between
* USB and Bluetooth. There are also some quirks in communicating * 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 * for libusb, but are not possible to support using hidraw if the
* kernel doesn't already know about them. * kernel doesn't already know about them.
*/ */
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3, SDL_FALSE); default_value = SDL_FALSE;
#else #else
/* Untested, default off */ /* Untested, default off */
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3, SDL_FALSE); default_value = SDL_FALSE;
#endif #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 static SDL_bool
@ -112,19 +117,6 @@ HIDAPI_DriverPS3_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name,
return SDL_FALSE; 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) static int ReadFeatureReport(SDL_hid_device *dev, Uint8 report_id, Uint8 *report, size_t length)
{ {
SDL_memset(report, 0, 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 static SDL_bool
HIDAPI_DriverPS3_InitDevice(SDL_HIDAPI_Device *device) 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); return HIDAPI_JoystickConnected(device, NULL);
} }
@ -190,59 +239,13 @@ HIDAPI_DriverPS3_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID
static SDL_bool static SDL_bool
HIDAPI_DriverPS3_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 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; ctx->joystick = joystick;
ctx->effects_updated = SDL_FALSE;
device->dev = SDL_hid_open_path(device->path, 0); ctx->rumble_left = 0;
if (!device->dev) { ctx->rumble_right = 0;
SDL_free(ctx); SDL_zeroa(ctx->last_state);
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);
}
}
/* Initialize player index (needed for setting LEDs) */ /* Initialize player index (needed for setting LEDs) */
ctx->player_index = SDL_JoystickGetPlayerIndex(joystick); ctx->player_index = SDL_JoystickGetPlayerIndex(joystick);
@ -498,8 +501,7 @@ HIDAPI_DriverPS3_UpdateDevice(SDL_HIDAPI_Device *device)
if (device->num_joysticks > 0) { if (device->num_joysticks > 0) {
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
} } else {
if (!joystick) {
return SDL_FALSE; return SDL_FALSE;
} }
@ -507,10 +509,19 @@ HIDAPI_DriverPS3_UpdateDevice(SDL_HIDAPI_Device *device)
#ifdef DEBUG_PS3_PROTOCOL #ifdef DEBUG_PS3_PROTOCOL
HIDAPI_DumpPacket("PS3 packet: size = %d", data, size); HIDAPI_DumpPacket("PS3 packet: size = %d", data, size);
#endif #endif
if (!joystick) {
continue;
}
if (size == 7) { if (size == 7) {
/* Seen on a ShanWan PS2 -> PS3 USB converter */ /* Seen on a ShanWan PS2 -> PS3 USB converter */
HIDAPI_DriverPS3_HandleMiniStatePacket(joystick, ctx, data, size); 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; continue;
} }
@ -538,7 +549,7 @@ HIDAPI_DriverPS3_UpdateDevice(SDL_HIDAPI_Device *device)
if (size < 0) { if (size < 0) {
/* Read error, device is disconnected */ /* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, joystick->instance_id); HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
} }
return (size >= 0); return (size >= 0);
} }
@ -546,15 +557,9 @@ HIDAPI_DriverPS3_UpdateDevice(SDL_HIDAPI_Device *device)
static void static void
HIDAPI_DriverPS3_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) HIDAPI_DriverPS3_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{ {
SDL_LockMutex(device->dev_lock); SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context;
{
SDL_hid_close(device->dev);
device->dev = NULL;
SDL_free(device->context); ctx->joystick = NULL;
device->context = NULL;
}
SDL_UnlockMutex(device->dev_lock);
} }
static void static void
@ -570,7 +575,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS3 =
HIDAPI_DriverPS3_UnregisterHints, HIDAPI_DriverPS3_UnregisterHints,
HIDAPI_DriverPS3_IsEnabled, HIDAPI_DriverPS3_IsEnabled,
HIDAPI_DriverPS3_IsSupportedDevice, HIDAPI_DriverPS3_IsSupportedDevice,
HIDAPI_DriverPS3_GetDeviceName,
HIDAPI_DriverPS3_InitDevice, HIDAPI_DriverPS3_InitDevice,
HIDAPI_DriverPS3_GetDevicePlayerIndex, HIDAPI_DriverPS3_GetDevicePlayerIndex,
HIDAPI_DriverPS3_SetDevicePlayerIndex, HIDAPI_DriverPS3_SetDevicePlayerIndex,

View file

@ -142,8 +142,6 @@ typedef struct {
Uint8 led_red; Uint8 led_red;
Uint8 led_green; Uint8 led_green;
Uint8 led_blue; Uint8 led_blue;
Uint8 volume;
Uint32 last_volume_check;
PS4StatePacket_t last_state; PS4StatePacket_t last_state;
} SDL_DriverPS4_Context; } 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; 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) static int ReadFeatureReport(SDL_hid_device *dev, Uint8 report_id, Uint8 *report, size_t length)
{ {
SDL_memset(report, 0, length); SDL_memset(report, 0, length);
@ -222,6 +211,106 @@ SetLedsForPlayerIndex(DS4EffectsState_t *effects, int player_index)
static SDL_bool static SDL_bool
HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device) 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); 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; SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
if (!ctx) { if (!ctx->joystick) {
return; return;
} }
@ -484,124 +573,28 @@ HIDAPI_DriverPS4_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID
static SDL_bool static SDL_bool
HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{ {
SDL_DriverPS4_Context *ctx; SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *) device->context;
Uint8 data[USB_PACKET_LENGTH];
int size;
SDL_bool enhanced_mode = SDL_FALSE;
ctx = (SDL_DriverPS4_Context *)SDL_calloc(1, sizeof(*ctx));
if (!ctx) {
SDL_OutOfMemory();
return SDL_FALSE;
}
ctx->device = device;
ctx->joystick = joystick; ctx->joystick = joystick;
ctx->last_packet = SDL_GetTicks(); ctx->last_packet = SDL_GetTicks();
ctx->report_sensors = SDL_FALSE;
device->dev = SDL_hid_open_path(device->path, 0); ctx->report_touchpad = SDL_FALSE;
if (!device->dev) { ctx->rumble_left = 0;
SDL_free(ctx); ctx->rumble_right = 0;
SDL_SetError("Couldn't open %s", device->path); ctx->color_set = SDL_FALSE;
return SDL_FALSE; SDL_zero(ctx->last_state);
}
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);
}
/* Initialize player index (needed for setting LEDs) */ /* Initialize player index (needed for setting LEDs) */
ctx->player_index = SDL_JoystickGetPlayerIndex(joystick); ctx->player_index = SDL_JoystickGetPlayerIndex(joystick);
/* Initialize the joystick capabilities /* Initialize the joystick capabilities */
* joystick->nbuttons = ctx->touchpad_supported ? 16 : 15;
* We can't dynamically add the touchpad button, so always report it here
*/
joystick->nbuttons = 16;
joystick->naxes = SDL_CONTROLLER_AXIS_MAX; joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
joystick->epowerlevel = ctx->is_bluetooth ? SDL_JOYSTICK_POWER_UNKNOWN : SDL_JOYSTICK_POWER_WIRED; 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); HIDAPI_DriverPS4_SetEnhancedMode(device, joystick);
} else { } else {
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE,
@ -879,8 +872,7 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
if (device->num_joysticks > 0) { if (device->num_joysticks > 0) {
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
} } else {
if (!joystick) {
return SDL_FALSE; return SDL_FALSE;
} }
@ -891,6 +883,10 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
++packet_count; ++packet_count;
ctx->last_packet = SDL_GetTicks(); ctx->last_packet = SDL_GetTicks();
if (!joystick) {
continue;
}
switch (data[0]) { switch (data[0]) {
case k_EPS4ReportIdUsbState: case k_EPS4ReportIdUsbState:
HIDAPI_DriverPS4_HandleStatePacket(joystick, device->dev, ctx, (PS4StatePacket_t *)&data[1]); 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) { if (size < 0) {
/* Read error, device is disconnected */ /* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, joystick->instance_id); HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
} }
return (size >= 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_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE,
SDL_PS4RumbleHintChanged, ctx); SDL_PS4RumbleHintChanged, ctx);
SDL_LockMutex(device->dev_lock); ctx->joystick = NULL;
{
SDL_hid_close(device->dev);
device->dev = NULL;
SDL_free(device->context);
device->context = NULL;
}
SDL_UnlockMutex(device->dev_lock);
} }
static void static void
@ -968,7 +956,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4 =
HIDAPI_DriverPS4_UnregisterHints, HIDAPI_DriverPS4_UnregisterHints,
HIDAPI_DriverPS4_IsEnabled, HIDAPI_DriverPS4_IsEnabled,
HIDAPI_DriverPS4_IsSupportedDevice, HIDAPI_DriverPS4_IsSupportedDevice,
HIDAPI_DriverPS4_GetDeviceName,
HIDAPI_DriverPS4_InitDevice, HIDAPI_DriverPS4_InitDevice,
HIDAPI_DriverPS4_GetDevicePlayerIndex, HIDAPI_DriverPS4_GetDevicePlayerIndex,
HIDAPI_DriverPS4_SetDevicePlayerIndex, HIDAPI_DriverPS4_SetDevicePlayerIndex,

View file

@ -256,15 +256,6 @@ HIDAPI_DriverPS5_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name,
return (type == SDL_CONTROLLER_TYPE_PS5) ? SDL_TRUE : SDL_FALSE; 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) static int ReadFeatureReport(SDL_hid_device *dev, Uint8 report_id, Uint8 *report, size_t length)
{ {
SDL_memset(report, 0, length); SDL_memset(report, 0, length);
@ -321,6 +312,112 @@ SetLightsForPlayerIndex(DS5EffectsState_t *effects, int player_index)
static SDL_bool static SDL_bool
HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device) 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); 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; SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
if (!ctx) { if (!ctx->joystick) {
return; return;
} }
@ -636,132 +733,31 @@ HIDAPI_DriverPS5_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID
static SDL_bool static SDL_bool
HIDAPI_DriverPS5_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) HIDAPI_DriverPS5_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{ {
SDL_DriverPS5_Context *ctx; SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
Uint8 data[USB_PACKET_LENGTH*2];
int size;
SDL_bool enhanced_mode = SDL_FALSE;
ctx = (SDL_DriverPS5_Context *)SDL_calloc(1, sizeof(*ctx));
if (!ctx) {
SDL_OutOfMemory();
return SDL_FALSE;
}
ctx->device = device;
ctx->joystick = joystick; ctx->joystick = joystick;
ctx->last_packet = SDL_GetTicks(); ctx->last_packet = SDL_GetTicks();
ctx->report_sensors = SDL_FALSE;
device->dev = SDL_hid_open_path(device->path, 0); ctx->report_touchpad = SDL_FALSE;
if (!device->dev) { ctx->rumble_left = 0;
SDL_free(ctx); ctx->rumble_right = 0;
SDL_SetError("Couldn't open %s", device->path); ctx->color_set = SDL_FALSE;
return SDL_FALSE; ctx->led_reset_state = k_EDS5LEDResetStateNone;
} SDL_zero(ctx->last_state);
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);
}
/* Initialize player index (needed for setting LEDs) */ /* Initialize player index (needed for setting LEDs) */
ctx->player_index = SDL_JoystickGetPlayerIndex(joystick); ctx->player_index = SDL_JoystickGetPlayerIndex(joystick);
ctx->player_lights = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED, SDL_TRUE); ctx->player_lights = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED, SDL_TRUE);
/* Initialize the joystick capabilities /* Initialize the joystick capabilities */
* joystick->nbuttons = ctx->touchpad_supported ? 17 : 15;
* We can't dynamically add the touchpad button, so always report it here
*/
joystick->nbuttons = 17;
joystick->naxes = SDL_CONTROLLER_AXIS_MAX; joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
joystick->epowerlevel = ctx->is_bluetooth ? SDL_JOYSTICK_POWER_UNKNOWN : SDL_JOYSTICK_POWER_WIRED; 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); HIDAPI_DriverPS5_SetEnhancedMode(device, joystick);
} else { } else {
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, 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_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED,
SDL_PS5PlayerLEDHintChanged, ctx); SDL_PS5PlayerLEDHintChanged, ctx);
return SDL_TRUE; return SDL_TRUE;
} }
@ -1183,8 +1180,7 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
if (device->num_joysticks > 0) { if (device->num_joysticks > 0) {
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
} } else {
if (!joystick) {
return SDL_FALSE; return SDL_FALSE;
} }
@ -1195,6 +1191,10 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
++packet_count; ++packet_count;
ctx->last_packet = SDL_GetTicks(); ctx->last_packet = SDL_GetTicks();
if (!joystick) {
continue;
}
switch (data[0]) { switch (data[0]) {
case k_EPS5ReportIdState: case k_EPS5ReportIdState:
if (size == 10 || size == 78) { if (size == 10 || size == 78) {
@ -1241,7 +1241,7 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
if (size < 0) { if (size < 0) {
/* Read error, device is disconnected */ /* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, joystick->instance_id); HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
} }
return (size >= 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_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED,
SDL_PS5PlayerLEDHintChanged, ctx); SDL_PS5PlayerLEDHintChanged, ctx);
SDL_LockMutex(device->dev_lock); ctx->joystick = NULL;
{
SDL_hid_close(device->dev);
device->dev = NULL;
SDL_free(device->context);
device->context = NULL;
}
SDL_UnlockMutex(device->dev_lock);
} }
static void static void
@ -1281,7 +1273,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS5 =
HIDAPI_DriverPS5_UnregisterHints, HIDAPI_DriverPS5_UnregisterHints,
HIDAPI_DriverPS5_IsEnabled, HIDAPI_DriverPS5_IsEnabled,
HIDAPI_DriverPS5_IsSupportedDevice, HIDAPI_DriverPS5_IsSupportedDevice,
HIDAPI_DriverPS5_GetDeviceName,
HIDAPI_DriverPS5_InitDevice, HIDAPI_DriverPS5_InitDevice,
HIDAPI_DriverPS5_GetDevicePlayerIndex, HIDAPI_DriverPS5_GetDevicePlayerIndex,
HIDAPI_DriverPS5_SetDevicePlayerIndex, HIDAPI_DriverPS5_SetDevicePlayerIndex,

View file

@ -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; 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 static SDL_bool
HIDAPI_DriverShield_InitDevice(SDL_HIDAPI_Device *device) 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); return HIDAPI_JoystickConnected(device, NULL);
} }
@ -133,7 +138,7 @@ HIDAPI_DriverShield_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystick
static int static int
HIDAPI_DriverShield_SendCommand(SDL_HIDAPI_Device *device, Uint8 cmd, const void *data, int size) 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; ShieldCommandReport_t cmd_pkt;
if (size > sizeof(cmd_pkt.payload)) { if (size > sizeof(cmd_pkt.payload)) {
@ -164,21 +169,14 @@ HIDAPI_DriverShield_SendCommand(SDL_HIDAPI_Device *device, Uint8 cmd, const void
static SDL_bool static SDL_bool
HIDAPI_DriverShield_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 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)); ctx->rumble_report_pending = SDL_FALSE;
if (!ctx) { ctx->rumble_update_pending = SDL_FALSE;
SDL_OutOfMemory(); ctx->left_motor_amplitude = 0;
return SDL_FALSE; ctx->right_motor_amplitude = 0;
} ctx->last_rumble_time = 0;
SDL_zeroa(ctx->last_state);
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;
/* Initialize the joystick capabilities */ /* Initialize the joystick capabilities */
joystick->nbuttons = 16; joystick->nbuttons = 16;
@ -186,7 +184,6 @@ HIDAPI_DriverShield_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN; joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
/* Request battery and charging info */ /* Request battery and charging info */
ctx->battery_level = SDL_JOYSTICK_POWER_UNKNOWN;
ctx->last_battery_query_time = SDL_GetTicks(); ctx->last_battery_query_time = SDL_GetTicks();
HIDAPI_DriverShield_SendCommand(device, CMD_CHARGE_STATE, NULL, 0); HIDAPI_DriverShield_SendCommand(device, CMD_CHARGE_STATE, NULL, 0);
HIDAPI_DriverShield_SendCommand(device, CMD_BATTERY_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) { if (device->num_joysticks > 0) {
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
} } else {
if (!joystick) {
return SDL_FALSE; return SDL_FALSE;
} }
@ -376,9 +372,13 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)
#ifdef DEBUG_SHIELD_PROTOCOL #ifdef DEBUG_SHIELD_PROTOCOL
HIDAPI_DumpPacket("NVIDIA SHIELD packet: size = %d", data, size); HIDAPI_DumpPacket("NVIDIA SHIELD packet: size = %d", data, size);
#endif #endif
/* Byte 0 is HID report ID */ /* Byte 0 is HID report ID */
switch (data[0]) { switch (data[0]) {
case k_ShieldReportIdControllerState: case k_ShieldReportIdControllerState:
if (!joystick) {
break;
}
HIDAPI_DriverShield_HandleStatePacket(joystick, ctx, data, size); HIDAPI_DriverShield_HandleStatePacket(joystick, ctx, data, size);
break; break;
case k_ShieldReportIdCommandResponse: case k_ShieldReportIdCommandResponse:
@ -390,7 +390,9 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)
break; break;
case CMD_CHARGE_STATE: case CMD_CHARGE_STATE:
ctx->charging = cmd_resp_report->payload[0] != 0; ctx->charging = cmd_resp_report->payload[0] != 0;
if (joystick) {
SDL_PrivateJoystickBatteryLevel(joystick, ctx->charging ? SDL_JOYSTICK_POWER_WIRED : ctx->battery_level); SDL_PrivateJoystickBatteryLevel(joystick, ctx->charging ? SDL_JOYSTICK_POWER_WIRED : ctx->battery_level);
}
break; break;
case CMD_BATTERY_STATE: case CMD_BATTERY_STATE:
switch (cmd_resp_report->payload[2]) { switch (cmd_resp_report->payload[2]) {
@ -412,7 +414,9 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)
ctx->battery_level = SDL_JOYSTICK_POWER_UNKNOWN; ctx->battery_level = SDL_JOYSTICK_POWER_UNKNOWN;
break; break;
} }
if (joystick) {
SDL_PrivateJoystickBatteryLevel(joystick, ctx->charging ? SDL_JOYSTICK_POWER_WIRED : ctx->battery_level); SDL_PrivateJoystickBatteryLevel(joystick, ctx->charging ? SDL_JOYSTICK_POWER_WIRED : ctx->battery_level);
}
break; break;
} }
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 */ /* 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(); ctx->last_battery_query_time = SDL_GetTicks();
HIDAPI_DriverShield_SendCommand(device, CMD_BATTERY_STATE, NULL, 0); HIDAPI_DriverShield_SendCommand(device, CMD_BATTERY_STATE, NULL, 0);
} }
@ -434,7 +438,7 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)
if (size < 0) { if (size < 0) {
/* Read error, device is disconnected */ /* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, joystick->instance_id); HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
} }
return (size >= 0); return (size >= 0);
} }
@ -442,17 +446,6 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)
static void static void
HIDAPI_DriverShield_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 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 static void
@ -468,7 +461,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverShield =
HIDAPI_DriverShield_UnregisterHints, HIDAPI_DriverShield_UnregisterHints,
HIDAPI_DriverShield_IsEnabled, HIDAPI_DriverShield_IsEnabled,
HIDAPI_DriverShield_IsSupportedDevice, HIDAPI_DriverShield_IsSupportedDevice,
HIDAPI_DriverShield_GetDeviceName,
HIDAPI_DriverShield_InitDevice, HIDAPI_DriverShield_InitDevice,
HIDAPI_DriverShield_GetDevicePlayerIndex, HIDAPI_DriverShield_GetDevicePlayerIndex,
HIDAPI_DriverShield_SetDevicePlayerIndex, HIDAPI_DriverShield_SetDevicePlayerIndex,

View file

@ -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; 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 static SDL_bool
HIDAPI_DriverStadia_InitDevice(SDL_HIDAPI_Device *device) 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); return HIDAPI_JoystickConnected(device, NULL);
} }
@ -99,21 +104,9 @@ HIDAPI_DriverStadia_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystick
static SDL_bool static SDL_bool
HIDAPI_DriverStadia_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 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)); SDL_zeroa(ctx->last_state);
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;
/* Initialize the joystick capabilities */ /* Initialize the joystick capabilities */
joystick->nbuttons = SDL_CONTROLLER_NUM_STADIA_BUTTONS; joystick->nbuttons = SDL_CONTROLLER_NUM_STADIA_BUTTONS;
@ -281,8 +274,7 @@ HIDAPI_DriverStadia_UpdateDevice(SDL_HIDAPI_Device *device)
if (device->num_joysticks > 0) { if (device->num_joysticks > 0) {
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
} } else {
if (!joystick) {
return SDL_FALSE; return SDL_FALSE;
} }
@ -290,12 +282,16 @@ HIDAPI_DriverStadia_UpdateDevice(SDL_HIDAPI_Device *device)
#ifdef DEBUG_STADIA_PROTOCOL #ifdef DEBUG_STADIA_PROTOCOL
HIDAPI_DumpPacket("Google Stadia packet: size = %d", data, size); HIDAPI_DumpPacket("Google Stadia packet: size = %d", data, size);
#endif #endif
if (!joystick) {
continue;
}
HIDAPI_DriverStadia_HandleStatePacket(joystick, ctx, data, size); HIDAPI_DriverStadia_HandleStatePacket(joystick, ctx, data, size);
} }
if (size < 0) { if (size < 0) {
/* Read error, device is disconnected */ /* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, joystick->instance_id); HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
} }
return (size >= 0); return (size >= 0);
} }
@ -303,17 +299,6 @@ HIDAPI_DriverStadia_UpdateDevice(SDL_HIDAPI_Device *device)
static void static void
HIDAPI_DriverStadia_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 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 static void
@ -329,7 +314,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverStadia =
HIDAPI_DriverStadia_UnregisterHints, HIDAPI_DriverStadia_UnregisterHints,
HIDAPI_DriverStadia_IsEnabled, HIDAPI_DriverStadia_IsEnabled,
HIDAPI_DriverStadia_IsSupportedDevice, HIDAPI_DriverStadia_IsSupportedDevice,
HIDAPI_DriverStadia_GetDeviceName,
HIDAPI_DriverStadia_InitDevice, HIDAPI_DriverStadia_InitDevice,
HIDAPI_DriverStadia_GetDevicePlayerIndex, HIDAPI_DriverStadia_GetDevicePlayerIndex,
HIDAPI_DriverStadia_SetDevicePlayerIndex, HIDAPI_DriverStadia_SetDevicePlayerIndex,

View file

@ -1022,15 +1022,20 @@ HIDAPI_DriverSteam_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name
return SDL_IsJoystickSteamController(vendor_id, product_id); 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 static SDL_bool
HIDAPI_DriverSteam_InitDevice(SDL_HIDAPI_Device *device) 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); return HIDAPI_JoystickConnected(device, NULL);
} }
@ -1048,27 +1053,18 @@ HIDAPI_DriverSteam_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickI
static SDL_bool static SDL_bool
HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 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; uint32_t update_rate_in_us = 0;
float update_rate_in_hz = 0.0f; float update_rate_in_hz = 0.0f;
ctx = (SDL_DriverSteam_Context *)SDL_calloc(1, sizeof(*ctx)); ctx->report_sensors = SDL_FALSE;
if (!ctx) { SDL_zero(ctx->m_assembler);
SDL_OutOfMemory(); SDL_zero(ctx->m_state);
goto error; SDL_zero(ctx->m_last_state);
}
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);
if (!ResetSteamController(device->dev, false, &update_rate_in_us)) { if (!ResetSteamController(device->dev, false, &update_rate_in_us)) {
SDL_SetError("Couldn't reset controller"); SDL_SetError("Couldn't reset controller");
goto error; return SDL_FALSE;
} }
if (update_rate_in_us > 0) { if (update_rate_in_us > 0) {
update_rate_in_hz = 1000000.0f / update_rate_in_us; 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); SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, update_rate_in_hz);
return SDL_TRUE; 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 static int
@ -1117,7 +1098,7 @@ HIDAPI_DriverSteam_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystic
static Uint32 static Uint32
HIDAPI_DriverSteam_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 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; return 0;
} }
@ -1166,8 +1147,7 @@ HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device *device)
if (device->num_joysticks > 0) { if (device->num_joysticks > 0) {
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
} } else {
if (!joystick) {
return SDL_FALSE; return SDL_FALSE;
} }
@ -1178,11 +1158,14 @@ HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device *device)
const Uint8 *pPacket; const Uint8 *pPacket;
r = ReadSteamController(device->dev, data, sizeof(data)); r = ReadSteamController(device->dev, data, sizeof(data));
if (r == 0) if (r == 0) {
{
break; break;
} }
if (!joystick) {
continue;
}
nPacketLength = 0; nPacketLength = 0;
if (r > 0) { if (r > 0) {
nPacketLength = WriteSegmentToSteamControllerPacketAssembler(&ctx->m_assembler, data, r); nPacketLength = WriteSegmentToSteamControllerPacketAssembler(&ctx->m_assembler, data, r);
@ -1280,18 +1263,8 @@ HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device *device)
static void static void
HIDAPI_DriverSteam_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) HIDAPI_DriverSteam_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_LockMutex(device->dev_lock);
{ {
CloseSteamController(device->dev); CloseSteamController(device->dev);
SDL_hid_close(device->dev);
device->dev = NULL;
SDL_free(device->context);
device->context = NULL;
}
SDL_UnlockMutex(device->dev_lock);
} }
static void static void
@ -1307,7 +1280,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteam =
HIDAPI_DriverSteam_UnregisterHints, HIDAPI_DriverSteam_UnregisterHints,
HIDAPI_DriverSteam_IsEnabled, HIDAPI_DriverSteam_IsEnabled,
HIDAPI_DriverSteam_IsSupportedDevice, HIDAPI_DriverSteam_IsSupportedDevice,
HIDAPI_DriverSteam_GetDeviceName,
HIDAPI_DriverSteam_InitDevice, HIDAPI_DriverSteam_InitDevice,
HIDAPI_DriverSteam_GetDevicePlayerIndex, HIDAPI_DriverSteam_GetDevicePlayerIndex,
HIDAPI_DriverSteam_SetDevicePlayerIndex, HIDAPI_DriverSteam_SetDevicePlayerIndex,

View file

@ -236,6 +236,7 @@ typedef struct
typedef struct { typedef struct {
SDL_HIDAPI_Device *device; SDL_HIDAPI_Device *device;
SDL_Joystick *joystick;
SDL_bool m_bInputOnly; SDL_bool m_bInputOnly;
SDL_bool m_bUsingBluetooth; SDL_bool m_bUsingBluetooth;
SDL_bool m_bIsGameCube; 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)); 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) static SDL_bool BReadDeviceInfo(SDL_DriverSwitch_Context *ctx)
{ {
SwitchSubcommandInputPacket_t *reply = NULL; 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]; SwitchProprietaryStatusPacket_t *status = (SwitchProprietaryStatusPacket_t *)&ctx->m_rgucReadBuffer[0];
size_t i; size_t i;
ctx->m_eControllerType = (ESwitchDeviceInfoControllerType)status->ucDeviceType; ctx->m_eControllerType = CalculateControllerType(ctx, (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;
}
for (i = 0; i < sizeof (ctx->m_rgucMACAddress); ++i) for (i = 0; i < sizeof (ctx->m_rgucMACAddress); ++i)
ctx->m_rgucMACAddress[i] = status->rgucMACAddress[ sizeof(ctx->m_rgucMACAddress) - i - 1 ]; 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)) { if (WriteSubcommand(ctx, k_eSwitchSubcommandIDs_RequestDeviceInfo, NULL, 0, &reply)) {
// Byte 2: Controller ID (1=LJC, 2=RJC, 3=Pro) // 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) // Bytes 4-9: MAC address (big-endian)
SDL_memcpy(ctx->m_rgucMACAddress, reply->deviceInfo.rgucMACAddress, sizeof(ctx->m_rgucMACAddress)); SDL_memcpy(ctx->m_rgucMACAddress, reply->deviceInfo.rgucMACAddress, sizeof(ctx->m_rgucMACAddress));
@ -909,6 +927,8 @@ static ESwitchDeviceInfoControllerType
ReadJoyConControllerType(SDL_HIDAPI_Device *device) ReadJoyConControllerType(SDL_HIDAPI_Device *device)
{ {
ESwitchDeviceInfoControllerType eControllerType = k_eSwitchDeviceInfoControllerType_Unknown; 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 */ /* 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)); SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)SDL_calloc(1, sizeof(*ctx));
@ -917,27 +937,17 @@ ReadJoyConControllerType(SDL_HIDAPI_Device *device)
ctx->m_bSyncWrite = SDL_TRUE; ctx->m_bSyncWrite = SDL_TRUE;
ctx->m_nMaxWriteAttempts = GetMaxWriteAttempts(device); 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) { for (attempts = 0; attempts < MAX_ATTEMPTS; ++attempts) {
if (WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Status, NULL, 0, SDL_TRUE)) { if (WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Status, NULL, 0, SDL_TRUE)) {
SwitchProprietaryStatusPacket_t *status = (SwitchProprietaryStatusPacket_t *)&ctx->m_rgucReadBuffer[0]; SwitchProprietaryStatusPacket_t *status = (SwitchProprietaryStatusPacket_t *)&ctx->m_rgucReadBuffer[0];
eControllerType = (ESwitchDeviceInfoControllerType) status->ucDeviceType; eControllerType = CalculateControllerType(ctx, (ESwitchDeviceInfoControllerType)status->ucDeviceType);
/* 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 { } else {
SwitchSubcommandInputPacket_t *reply = NULL; SwitchSubcommandInputPacket_t *reply = NULL;
ctx->m_bUsingBluetooth = SDL_TRUE; ctx->m_bUsingBluetooth = SDL_TRUE;
if (WriteSubcommand(ctx, k_eSwitchSubcommandIDs_RequestDeviceInfo, NULL, 0, &reply)) { if (WriteSubcommand(ctx, k_eSwitchSubcommandIDs_RequestDeviceInfo, NULL, 0, &reply)) {
eControllerType = (ESwitchDeviceInfoControllerType)reply->deviceInfo.ucDeviceType; eControllerType = CalculateControllerType(ctx, (ESwitchDeviceInfoControllerType)reply->deviceInfo.ucDeviceType);
} }
} }
if (eControllerType == k_eSwitchDeviceInfoControllerType_Unknown) { if (eControllerType == k_eSwitchDeviceInfoControllerType_Unknown) {
@ -948,9 +958,6 @@ ReadJoyConControllerType(SDL_HIDAPI_Device *device)
break; break;
} }
} }
SDL_hid_close(device->dev);
device->dev = NULL;
}
SDL_free(ctx); SDL_free(ctx);
} }
return eControllerType; return eControllerType;
@ -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; 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 static void
UpdateDeviceIdentity(SDL_HIDAPI_Device *device) UpdateDeviceIdentity(SDL_HIDAPI_Device *device)
{ {
ESwitchDeviceInfoControllerType eControllerType = (ESwitchDeviceInfoControllerType)device->guid.data[15]; SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
const char *name = NULL; char serial[18];
switch (eControllerType) { switch (ctx->m_eControllerType) {
case k_eSwitchDeviceInfoControllerType_JoyConLeft: case k_eSwitchDeviceInfoControllerType_JoyConLeft:
name = "Nintendo Switch Joy-Con (L)"; HIDAPI_SetDeviceName(device, "Nintendo Switch Joy-Con (L)");
SDL_SetJoystickGUIDProduct(&device->guid, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT); HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT);
break; break;
case k_eSwitchDeviceInfoControllerType_JoyConRight: case k_eSwitchDeviceInfoControllerType_JoyConRight:
name = "Nintendo Switch Joy-Con (R)"; HIDAPI_SetDeviceName(device, "Nintendo Switch Joy-Con (R)");
SDL_SetJoystickGUIDProduct(&device->guid, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT); HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT);
break; break;
case k_eSwitchDeviceInfoControllerType_ProController: case k_eSwitchDeviceInfoControllerType_ProController:
name = "Nintendo Switch Pro Controller"; HIDAPI_SetDeviceName(device, "Nintendo Switch Pro Controller");
SDL_SetJoystickGUIDProduct(&device->guid, USB_PRODUCT_NINTENDO_SWITCH_PRO); HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_SWITCH_PRO);
break; break;
case k_eSwitchDeviceInfoControllerType_NESLeft: case k_eSwitchDeviceInfoControllerType_NESLeft:
name = "Nintendo NES Controller (L)"; HIDAPI_SetDeviceName(device, "Nintendo NES Controller (L)");
break; break;
case k_eSwitchDeviceInfoControllerType_NESRight: case k_eSwitchDeviceInfoControllerType_NESRight:
name = "Nintendo NES Controller (R)"; HIDAPI_SetDeviceName(device, "Nintendo NES Controller (R)");
break; break;
case k_eSwitchDeviceInfoControllerType_SNES: case k_eSwitchDeviceInfoControllerType_SNES:
name = "Nintendo SNES Controller"; HIDAPI_SetDeviceName(device, "Nintendo SNES Controller");
SDL_SetJoystickGUIDProduct(&device->guid, USB_PRODUCT_NINTENDO_SNES_CONTROLLER); HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_SNES_CONTROLLER);
break; break;
case k_eSwitchDeviceInfoControllerType_N64: case k_eSwitchDeviceInfoControllerType_N64:
name = "Nintendo N64 Controller"; HIDAPI_SetDeviceName(device, "Nintendo N64 Controller");
device->product_id = USB_PRODUCT_NINTENDO_N64_CONTROLLER; HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_N64_CONTROLLER);
break; break;
case k_eSwitchDeviceInfoControllerType_SEGA_Genesis: case k_eSwitchDeviceInfoControllerType_SEGA_Genesis:
name = "Nintendo SEGA Genesis Controller"; HIDAPI_SetDeviceName(device, "Nintendo SEGA Genesis Controller");
SDL_SetJoystickGUIDProduct(&device->guid, USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER); HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER);
break; break;
default: default:
break; break;
} }
device->guid.data[15] = ctx->m_eControllerType;
if (name && (!name || SDL_strcmp(name, device->name) != 0)) { SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
SDL_free(device->name); ctx->m_rgucMACAddress[0],
device->name = SDL_strdup(name); ctx->m_rgucMACAddress[1],
SDL_SetJoystickGUIDCRC(&device->guid, SDL_crc16(0, name, SDL_strlen(name))); ctx->m_rgucMACAddress[2],
} ctx->m_rgucMACAddress[3],
ctx->m_rgucMACAddress[4],
ctx->m_rgucMACAddress[5]);
HIDAPI_SetDeviceSerial(device, serial);
} }
static SDL_bool static SDL_bool
HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *device) HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *device)
{ {
/* The NES controllers need additional fix up, since we can't detect them without opening the device */ SDL_DriverSwitch_Context *ctx;
if (device->vendor_id == USB_VENDOR_NINTENDO) {
ESwitchDeviceInfoControllerType eControllerType = ReadJoyConControllerType(device); ctx = (SDL_DriverSwitch_Context *)SDL_calloc(1, sizeof(*ctx));
switch (eControllerType) { if (!ctx) {
case k_eSwitchDeviceInfoControllerType_Unknown: SDL_OutOfMemory();
/* This might be a Joy-Con that's missing from a charging grip slot */ return SDL_FALSE;
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;
} }
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;
} }
break;
default: /* Find out whether or not we can send output reports */
device->guid.data[15] = eControllerType; ctx->m_bInputOnly = SDL_IsJoystickNintendoSwitchProInputOnly(device->vendor_id, device->product_id);
break; 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); UpdateDeviceIdentity(device);
} }
return HIDAPI_JoystickConnected(device, NULL); 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; SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
if (!ctx) { if (!ctx->joystick) {
return; return;
} }
@ -1285,41 +1262,22 @@ HIDAPI_DriverSwitch_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystick
static SDL_bool static SDL_bool
HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 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; Uint8 input_mode;
ctx = (SDL_DriverSwitch_Context *)SDL_calloc(1, sizeof(*ctx)); ctx->joystick = joystick;
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_nMaxWriteAttempts = GetMaxWriteAttempts(device);
ctx->m_bSyncWrite = SDL_TRUE; 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) { if (!ctx->m_bInputOnly) {
/* Initialize rumble data */ /* Initialize rumble data */
SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]); SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]); SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]);
if (!BReadDeviceInfo(ctx)) {
SDL_SetError("Couldn't read device info");
goto error;
}
if (!ctx->m_bUsingBluetooth) { if (!ctx->m_bUsingBluetooth) {
if (!BTrySetupUSB(ctx)) { if (!BTrySetupUSB(ctx)) {
SDL_SetError("Couldn't setup USB mode"); 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)) { if (!LoadStickCalibration(ctx, input_mode)) {
SDL_SetError("Couldn't load stick calibration"); SDL_SetError("Couldn't load stick calibration");
goto error; return SDL_FALSE;
} }
if (!LoadIMUCalibration(ctx)) { if (!LoadIMUCalibration(ctx)) {
SDL_SetError("Couldn't load sensor calibration"); SDL_SetError("Couldn't load sensor calibration");
goto error; return SDL_FALSE;
} }
if (!SetVibrationEnabled(ctx, 1)) { if (!SetVibrationEnabled(ctx, 1)) {
SDL_SetError("Couldn't enable vibration"); SDL_SetError("Couldn't enable vibration");
goto error; return SDL_FALSE;
} }
/* Set desired input mode */ /* Set desired input mode */
if (!SetInputMode(ctx, input_mode)) { if (!SetInputMode(ctx, input_mode)) {
SDL_SetError("Couldn't set input mode"); SDL_SetError("Couldn't set input mode");
goto error; return SDL_FALSE;
} }
/* Start sending USB reports */ /* 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 */ /* ForceUSB doesn't generate an ACK, so don't wait for a reply */
if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_ForceUSB, NULL, 0, SDL_FALSE)) { if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_ForceUSB, NULL, 0, SDL_FALSE)) {
SDL_SetError("Couldn't start USB reports"); 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); 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)) { 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(); ctx->m_unLastIMUReset = ctx->m_unLastInput = SDL_GetTicks();
return SDL_TRUE; 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 static int
@ -2142,8 +2063,7 @@ HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device)
if (device->num_joysticks > 0) { if (device->num_joysticks > 0) {
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
} } else {
if (!joystick) {
return SDL_FALSE; return SDL_FALSE;
} }
@ -2153,6 +2073,7 @@ HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device)
#ifdef DEBUG_SWITCH_PROTOCOL #ifdef DEBUG_SWITCH_PROTOCOL
HIDAPI_DumpPacket("Nintendo Switch packet: size = %d", ctx->m_rgucReadBuffer, size); HIDAPI_DumpPacket("Nintendo Switch packet: size = %d", ctx->m_rgucReadBuffer, size);
#endif #endif
if (joystick) {
if (ctx->m_bInputOnly) { if (ctx->m_bInputOnly) {
HandleInputOnlyControllerState(joystick, ctx, (SwitchInputOnlyControllerStatePacket_t *)&ctx->m_rgucReadBuffer[0]); HandleInputOnlyControllerState(joystick, ctx, (SwitchInputOnlyControllerStatePacket_t *)&ctx->m_rgucReadBuffer[0]);
} else { } else {
@ -2167,9 +2088,11 @@ HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device)
break; break;
} }
} }
}
ctx->m_unLastInput = now; ctx->m_unLastInput = now;
} }
if (joystick) {
if (!ctx->m_bInputOnly && !ctx->m_bUsingBluetooth && if (!ctx->m_bInputOnly && !ctx->m_bUsingBluetooth &&
ctx->device->product_id != USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP) { ctx->device->product_id != USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP) {
const Uint32 INPUT_WAIT_TIMEOUT_MS = 100; const Uint32 INPUT_WAIT_TIMEOUT_MS = 100;
@ -2184,6 +2107,7 @@ HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device)
size = -1; size = -1;
} }
} }
}
if (ctx->m_bRumblePending || ctx->m_bRumbleZeroPending) { if (ctx->m_bRumblePending || ctx->m_bRumbleZeroPending) {
HIDAPI_DriverSwitch_SendPendingRumble(ctx); HIDAPI_DriverSwitch_SendPendingRumble(ctx);
@ -2197,7 +2121,7 @@ HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device)
if (size < 0) { if (size < 0) {
/* Read error, device is disconnected */ /* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, joystick->instance_id); HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
} }
return (size >= 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_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED,
SDL_PlayerLEDHintChanged, ctx); SDL_PlayerLEDHintChanged, ctx);
SDL_LockMutex(device->dev_lock); ctx->joystick = NULL;
{
SDL_hid_close(device->dev);
device->dev = NULL;
SDL_free(device->context);
device->context = NULL;
}
SDL_UnlockMutex(device->dev_lock);
} }
static void static void
@ -2251,7 +2167,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverNintendoClassic =
HIDAPI_DriverNintendoClassic_UnregisterHints, HIDAPI_DriverNintendoClassic_UnregisterHints,
HIDAPI_DriverNintendoClassic_IsEnabled, HIDAPI_DriverNintendoClassic_IsEnabled,
HIDAPI_DriverNintendoClassic_IsSupportedDevice, HIDAPI_DriverNintendoClassic_IsSupportedDevice,
HIDAPI_DriverSwitch_GetDeviceName,
HIDAPI_DriverSwitch_InitDevice, HIDAPI_DriverSwitch_InitDevice,
HIDAPI_DriverSwitch_GetDevicePlayerIndex, HIDAPI_DriverSwitch_GetDevicePlayerIndex,
HIDAPI_DriverSwitch_SetDevicePlayerIndex, HIDAPI_DriverSwitch_SetDevicePlayerIndex,
@ -2275,7 +2190,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverJoyCons =
HIDAPI_DriverJoyCons_UnregisterHints, HIDAPI_DriverJoyCons_UnregisterHints,
HIDAPI_DriverJoyCons_IsEnabled, HIDAPI_DriverJoyCons_IsEnabled,
HIDAPI_DriverJoyCons_IsSupportedDevice, HIDAPI_DriverJoyCons_IsSupportedDevice,
HIDAPI_DriverSwitch_GetDeviceName,
HIDAPI_DriverSwitch_InitDevice, HIDAPI_DriverSwitch_InitDevice,
HIDAPI_DriverSwitch_GetDevicePlayerIndex, HIDAPI_DriverSwitch_GetDevicePlayerIndex,
HIDAPI_DriverSwitch_SetDevicePlayerIndex, HIDAPI_DriverSwitch_SetDevicePlayerIndex,
@ -2299,7 +2213,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch =
HIDAPI_DriverSwitch_UnregisterHints, HIDAPI_DriverSwitch_UnregisterHints,
HIDAPI_DriverSwitch_IsEnabled, HIDAPI_DriverSwitch_IsEnabled,
HIDAPI_DriverSwitch_IsSupportedDevice, HIDAPI_DriverSwitch_IsSupportedDevice,
HIDAPI_DriverSwitch_GetDeviceName,
HIDAPI_DriverSwitch_InitDevice, HIDAPI_DriverSwitch_InitDevice,
HIDAPI_DriverSwitch_GetDevicePlayerIndex, HIDAPI_DriverSwitch_GetDevicePlayerIndex,
HIDAPI_DriverSwitch_SetDevicePlayerIndex, HIDAPI_DriverSwitch_SetDevicePlayerIndex,

View file

@ -131,6 +131,7 @@ typedef struct {
typedef struct { typedef struct {
SDL_HIDAPI_Device *device; SDL_HIDAPI_Device *device;
SDL_Joystick *joystick;
EWiiCommunicationState m_eCommState; EWiiCommunicationState m_eCommState;
EWiiExtensionControllerType m_eExtensionControllerType; EWiiExtensionControllerType m_eExtensionControllerType;
SDL_bool m_bUseButtonLabels; SDL_bool m_bUseButtonLabels;
@ -185,12 +186,6 @@ HIDAPI_DriverWii_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name,
return SDL_FALSE; 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) static int ReadInput(SDL_DriverWii_Context *ctx)
{ {
int size; int size;
@ -671,17 +666,12 @@ static void SDLCALL SDL_PlayerLEDHintChanged(void *userdata, const char *name, c
static EWiiExtensionControllerType static EWiiExtensionControllerType
ReadExtensionControllerType(SDL_HIDAPI_Device *device) ReadExtensionControllerType(SDL_HIDAPI_Device *device)
{ {
SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)device->context;
EWiiExtensionControllerType eExtensionControllerType = k_eWiiExtensionControllerType_Unknown; EWiiExtensionControllerType eExtensionControllerType = k_eWiiExtensionControllerType_Unknown;
/* 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; const int MAX_ATTEMPTS = 20;
int attempts = 0; int attempts = 0;
/* Create enough of a context to read the controller type from the device */
for (attempts = 0; attempts < MAX_ATTEMPTS; ++attempts) { for (attempts = 0; attempts < MAX_ATTEMPTS; ++attempts) {
Uint16 extension; Uint16 extension;
if (SendExtensionIdentify(ctx, SDL_TRUE) && if (SendExtensionIdentify(ctx, SDL_TRUE) &&
@ -706,52 +696,50 @@ ReadExtensionControllerType(SDL_HIDAPI_Device *device)
break; break;
} }
} }
SDL_hid_close(device->dev);
device->dev = NULL;
}
SDL_free(ctx);
}
return eExtensionControllerType; return eExtensionControllerType;
} }
static void static void
UpdateDeviceIdentity(SDL_HIDAPI_Device *device) UpdateDeviceIdentity(SDL_HIDAPI_Device *device)
{ {
EWiiExtensionControllerType eExtensionControllerType = (EWiiExtensionControllerType)device->guid.data[15]; SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)device->context;
const char *name = NULL;
switch (eExtensionControllerType) { switch (ctx->m_eExtensionControllerType) {
case k_eWiiExtensionControllerType_None: case k_eWiiExtensionControllerType_None:
name = "Nintendo Wii Remote"; HIDAPI_SetDeviceName(device, "Nintendo Wii Remote");
break; break;
case k_eWiiExtensionControllerType_Nunchuk: case k_eWiiExtensionControllerType_Nunchuk:
name = "Nintendo Wii Remote with Nunchuk"; HIDAPI_SetDeviceName(device, "Nintendo Wii Remote with Nunchuk");
break; break;
case k_eWiiExtensionControllerType_Gamepad: case k_eWiiExtensionControllerType_Gamepad:
name = "Nintendo Wii Remote with Classic Controller"; HIDAPI_SetDeviceName(device, "Nintendo Wii Remote with Classic Controller");
break; break;
case k_eWiiExtensionControllerType_WiiUPro: case k_eWiiExtensionControllerType_WiiUPro:
name = "Nintendo Wii U Pro Controller"; HIDAPI_SetDeviceName(device, "Nintendo Wii U Pro Controller");
break; break;
default: default:
name = "Nintendo Wii Remote with Unknown Extension"; HIDAPI_SetDeviceName(device, "Nintendo Wii Remote with Unknown Extension");
break; break;
} }
if (name && (!name || SDL_strcmp(name, device->name) != 0)) { device->guid.data[15] = ctx->m_eExtensionControllerType;
SDL_free(device->name);
device->name = SDL_strdup(name);
SDL_SetJoystickGUIDCRC(&device->guid, SDL_crc16(0, name, SDL_strlen(name)));
}
} }
static SDL_bool static SDL_bool
HIDAPI_DriverWii_InitDevice(SDL_HIDAPI_Device *device) HIDAPI_DriverWii_InitDevice(SDL_HIDAPI_Device *device)
{ {
if (device->vendor_id == USB_VENDOR_NINTENDO) { SDL_DriverWii_Context *ctx;
EWiiExtensionControllerType eExtensionControllerType;
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); UpdateDeviceIdentity(device);
} }
return HIDAPI_JoystickConnected(device, NULL); return HIDAPI_JoystickConnected(device, NULL);
@ -766,9 +754,9 @@ HIDAPI_DriverWii_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID
static void static void
HIDAPI_DriverWii_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) 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; return;
} }
@ -780,23 +768,9 @@ HIDAPI_DriverWii_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID
static SDL_bool static SDL_bool
HIDAPI_DriverWii_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 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)); ctx->joystick = joystick;
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];
InitializeExtension(ctx); InitializeExtension(ctx);
@ -841,21 +815,6 @@ HIDAPI_DriverWii_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
ctx->m_unLastInput = SDL_GetTicks(); ctx->m_unLastInput = SDL_GetTicks();
return SDL_TRUE; 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 static int
@ -1509,16 +1468,16 @@ HIDAPI_DriverWii_UpdateDevice(SDL_HIDAPI_Device *device)
if (device->num_joysticks > 0) { if (device->num_joysticks > 0) {
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
} } else {
if (!joystick) {
return SDL_FALSE; return SDL_FALSE;
} }
now = SDL_GetTicks(); now = SDL_GetTicks();
while ((size = ReadInput(ctx)) > 0) { while ((size = ReadInput(ctx)) > 0) {
if (joystick) {
HandleInput(ctx, joystick); HandleInput(ctx, joystick);
}
ctx->m_unLastInput = now; ctx->m_unLastInput = now;
} }
@ -1533,6 +1492,7 @@ HIDAPI_DriverWii_UpdateDevice(SDL_HIDAPI_Device *device)
size = -1; size = -1;
} }
if (joystick) {
/* These checks aren't needed on the Wii U Pro Controller */ /* These checks aren't needed on the Wii U Pro Controller */
if (ctx->m_eExtensionControllerType != k_eWiiExtensionControllerType_WiiUPro) { if (ctx->m_eExtensionControllerType != k_eWiiExtensionControllerType_WiiUPro) {
@ -1559,10 +1519,11 @@ HIDAPI_DriverWii_UpdateDevice(SDL_HIDAPI_Device *device)
ctx->m_unLastStatus = now; ctx->m_unLastStatus = now;
} }
} }
}
if (size < 0 || ctx->m_bDisconnected) { if (size < 0 || ctx->m_bDisconnected) {
/* Read error, device is disconnected */ /* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, joystick->instance_id); HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
} }
return (size >= 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_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_WII_PLAYER_LED,
SDL_PlayerLEDHintChanged, ctx); SDL_PlayerLEDHintChanged, ctx);
SDL_LockMutex(device->dev_lock); ctx->joystick = NULL;
{
SDL_hid_close(device->dev);
device->dev = NULL;
SDL_free(device->context);
device->context = NULL;
}
SDL_UnlockMutex(device->dev_lock);
} }
static void static void
@ -1602,7 +1555,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverWii =
HIDAPI_DriverWii_UnregisterHints, HIDAPI_DriverWii_UnregisterHints,
HIDAPI_DriverWii_IsEnabled, HIDAPI_DriverWii_IsEnabled,
HIDAPI_DriverWii_IsSupportedDevice, HIDAPI_DriverWii_IsSupportedDevice,
HIDAPI_DriverWii_GetDeviceName,
HIDAPI_DriverWii_InitDevice, HIDAPI_DriverWii_InitDevice,
HIDAPI_DriverWii_GetDevicePlayerIndex, HIDAPI_DriverWii_GetDevicePlayerIndex,
HIDAPI_DriverWii_SetDevicePlayerIndex, HIDAPI_DriverWii_SetDevicePlayerIndex,

View file

@ -40,6 +40,7 @@
typedef struct { typedef struct {
SDL_HIDAPI_Device *device; SDL_HIDAPI_Device *device;
SDL_Joystick *joystick;
int player_index; int player_index;
SDL_bool player_lights; SDL_bool player_lights;
Uint8 last_state[USB_PACKET_LENGTH]; Uint8 last_state[USB_PACKET_LENGTH];
@ -108,12 +109,6 @@ HIDAPI_DriverXbox360_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *na
#endif #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) static SDL_bool SetSlotLED(SDL_hid_device *dev, Uint8 slot, SDL_bool on)
{ {
const SDL_bool blink = SDL_FALSE; const SDL_bool blink = SDL_FALSE;
@ -151,6 +146,17 @@ static void SDLCALL SDL_PlayerLEDHintChanged(void *userdata, const char *name, c
static SDL_bool static SDL_bool
HIDAPI_DriverXbox360_InitDevice(SDL_HIDAPI_Device *device) 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); 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; SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
if (!ctx) { if (!ctx->joystick) {
return; return;
} }
@ -177,22 +183,10 @@ HIDAPI_DriverXbox360_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystic
static SDL_bool static SDL_bool
HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 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)); ctx->joystick = joystick;
if (!ctx) { SDL_zeroa(ctx->last_state);
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;
/* Initialize player index (needed for setting LEDs) */ /* Initialize player index (needed for setting LEDs) */
ctx->player_index = SDL_JoystickGetPlayerIndex(joystick); ctx->player_index = SDL_JoystickGetPlayerIndex(joystick);
@ -343,8 +337,7 @@ HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device)
if (device->num_joysticks > 0) { if (device->num_joysticks > 0) {
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
} } else {
if (!joystick) {
return SDL_FALSE; return SDL_FALSE;
} }
@ -352,6 +345,10 @@ HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device)
#ifdef DEBUG_XBOX_PROTOCOL #ifdef DEBUG_XBOX_PROTOCOL
HIDAPI_DumpPacket("Xbox 360 packet: size = %d", data, size); HIDAPI_DumpPacket("Xbox 360 packet: size = %d", data, size);
#endif #endif
if (!joystick) {
continue;
}
if (data[0] == 0x00) { if (data[0] == 0x00) {
HIDAPI_DriverXbox360_HandleStatePacket(joystick, ctx, data, size); HIDAPI_DriverXbox360_HandleStatePacket(joystick, ctx, data, size);
} }
@ -359,7 +356,7 @@ HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device)
if (size < 0) { if (size < 0) {
/* Read error, device is disconnected */ /* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, joystick->instance_id); HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
} }
return (size >= 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_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED,
SDL_PlayerLEDHintChanged, ctx); SDL_PlayerLEDHintChanged, ctx);
SDL_LockMutex(device->dev_lock); ctx->joystick = NULL;
{
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 static void
@ -398,7 +385,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 =
HIDAPI_DriverXbox360_UnregisterHints, HIDAPI_DriverXbox360_UnregisterHints,
HIDAPI_DriverXbox360_IsEnabled, HIDAPI_DriverXbox360_IsEnabled,
HIDAPI_DriverXbox360_IsSupportedDevice, HIDAPI_DriverXbox360_IsSupportedDevice,
HIDAPI_DriverXbox360_GetDeviceName,
HIDAPI_DriverXbox360_InitDevice, HIDAPI_DriverXbox360_InitDevice,
HIDAPI_DriverXbox360_GetDevicePlayerIndex, HIDAPI_DriverXbox360_GetDevicePlayerIndex,
HIDAPI_DriverXbox360_SetDevicePlayerIndex, HIDAPI_DriverXbox360_SetDevicePlayerIndex,

View file

@ -41,7 +41,6 @@
typedef struct { typedef struct {
SDL_HIDAPI_Device *device; SDL_HIDAPI_Device *device;
SDL_bool connected; SDL_bool connected;
SDL_bool opened;
int player_index; int player_index;
SDL_bool player_lights; SDL_bool player_lights;
Uint8 last_state[USB_PACKET_LENGTH]; Uint8 last_state[USB_PACKET_LENGTH];
@ -86,12 +85,6 @@ HIDAPI_DriverXbox360W_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *n
return SDL_FALSE; 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) static SDL_bool SetSlotLED(SDL_hid_device *dev, Uint8 slot, SDL_bool on)
{ {
const SDL_bool blink = SDL_FALSE; 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 */ /* Requests controller presence information from the wireless dongle */
const Uint8 init_packet[] = { 0x08, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 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)); ctx = (SDL_DriverXbox360W_Context *)SDL_calloc(1, sizeof(*ctx));
if (!ctx) { if (!ctx) {
SDL_OutOfMemory(); SDL_OutOfMemory();
@ -157,12 +152,6 @@ HIDAPI_DriverXbox360W_InitDevice(SDL_HIDAPI_Device *device)
} }
ctx->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; device->context = ctx;
if (SDL_hid_write(device->dev, init_packet, sizeof(init_packet)) != sizeof(init_packet)) { 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); SDL_zeroa(ctx->last_state);
ctx->opened = SDL_TRUE;
/* Initialize player index (needed for setting LEDs) */ /* Initialize player index (needed for setting LEDs) */
ctx->player_index = SDL_JoystickGetPlayerIndex(joystick); ctx->player_index = SDL_JoystickGetPlayerIndex(joystick);
ctx->player_lights = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED, SDL_TRUE); 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 && device->num_joysticks > 0) {
if (size < 0) {
/* Read error, device is disconnected */ /* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, joystick->instance_id); HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
}
} }
return (size >= 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_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED,
SDL_PlayerLEDHintChanged, ctx); SDL_PlayerLEDHintChanged, ctx);
ctx->opened = SDL_FALSE;
} }
static void static void
HIDAPI_DriverXbox360W_FreeDevice(SDL_HIDAPI_Device *device) 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 = SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W =
@ -409,7 +383,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W =
HIDAPI_DriverXbox360W_UnregisterHints, HIDAPI_DriverXbox360W_UnregisterHints,
HIDAPI_DriverXbox360W_IsEnabled, HIDAPI_DriverXbox360W_IsEnabled,
HIDAPI_DriverXbox360W_IsSupportedDevice, HIDAPI_DriverXbox360W_IsSupportedDevice,
HIDAPI_DriverXbox360W_GetDeviceName,
HIDAPI_DriverXbox360W_InitDevice, HIDAPI_DriverXbox360W_InitDevice,
HIDAPI_DriverXbox360W_GetDevicePlayerIndex, HIDAPI_DriverXbox360W_GetDevicePlayerIndex,
HIDAPI_DriverXbox360W_SetDevicePlayerIndex, HIDAPI_DriverXbox360W_SetDevicePlayerIndex,

View file

@ -106,7 +106,6 @@ typedef struct {
Uint32 start_time; Uint32 start_time;
Uint8 sequence; Uint8 sequence;
Uint32 send_time; Uint32 send_time;
Uint8 last_state[USB_PACKET_LENGTH];
SDL_bool has_guide_packet; SDL_bool has_guide_packet;
SDL_bool has_color_led; SDL_bool has_color_led;
SDL_bool has_paddles; SDL_bool has_paddles;
@ -116,6 +115,7 @@ typedef struct {
Uint8 high_frequency_rumble; Uint8 high_frequency_rumble;
Uint8 left_trigger_rumble; Uint8 left_trigger_rumble;
Uint8 right_trigger_rumble; Uint8 right_trigger_rumble;
Uint8 last_state[USB_PACKET_LENGTH];
} SDL_DriverXboxOne_Context; } SDL_DriverXboxOne_Context;
static SDL_bool 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; 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 static SDL_bool
HIDAPI_DriverXboxOne_InitDevice(SDL_HIDAPI_Device *device) 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; SDL_DriverXboxOne_Context *ctx;
@ -343,12 +317,6 @@ HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst
return SDL_FALSE; 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; device->context = ctx;
ctx->vendor_id = device->vendor_id; 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); SDL_Log("Controller version: %d (0x%.4x)\n", device->version, device->version);
#endif #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 */ /* Initialize the joystick capabilities */
joystick->nbuttons = 15; joystick->nbuttons = 15;
if (ctx->has_share_button) { if (ctx->has_share_button) {
@ -975,12 +968,19 @@ HIDAPI_DriverXboxOne_UpdateInitState(SDL_HIDAPI_Device *device, SDL_DriverXboxOn
} }
static SDL_bool 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_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
SDL_Joystick *joystick = NULL;
Uint8 data[USB_PACKET_LENGTH]; Uint8 data[USB_PACKET_LENGTH];
int size; 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) { while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
#ifdef DEBUG_XBOX_PROTOCOL #ifdef DEBUG_XBOX_PROTOCOL
HIDAPI_DumpPacket("Xbox One packet: size = %d", data, size); 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) { if (ctx->bluetooth) {
switch (data[0]) { switch (data[0]) {
case 0x01: case 0x01:
if (!joystick) {
break;
}
if (size >= 16) { if (size >= 16) {
HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(joystick, ctx, data, size); HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(joystick, ctx, data, size);
} else { } else {
@ -997,9 +1000,15 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
} }
break; break;
case 0x02: case 0x02:
if (!joystick) {
break;
}
HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(joystick, ctx, data, size); HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(joystick, ctx, data, size);
break; break;
case 0x04: case 0x04:
if (!joystick) {
break;
}
HIDAPI_DriverXboxOneBluetooth_HandleBatteryPacket(joystick, ctx, data, size); HIDAPI_DriverXboxOneBluetooth_HandleBatteryPacket(joystick, ctx, data, size);
break; break;
default: default:
@ -1045,6 +1054,10 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
break; break;
case 0x03: case 0x03:
/* Controller status update */ /* Controller status update */
if (!joystick) {
/* We actually want to handle this packet any time it arrives */
/*break;*/
}
HIDAPI_DriverXboxOne_HandleStatusPacket(joystick, ctx, data, size); HIDAPI_DriverXboxOne_HandleStatusPacket(joystick, ctx, data, size);
break; break;
case 0x04: case 0x04:
@ -1054,6 +1067,9 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
/* Unknown chatty controller information, sent by both sides */ /* Unknown chatty controller information, sent by both sides */
break; break;
case 0x07: case 0x07:
if (!joystick) {
break;
}
HIDAPI_DriverXboxOne_HandleModePacket(joystick, ctx, data, size); HIDAPI_DriverXboxOne_HandleModePacket(joystick, ctx, data, size);
break; break;
case 0x1E: 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: The controller sends that in response to this request:
0x1E 0x30 0x07 0x01 0x04 0x1E 0x30 0x07 0x01 0x04
*/ */
if (!joystick) {
break;
}
#ifdef SET_SERIAL_AFTER_OPEN #ifdef SET_SERIAL_AFTER_OPEN
if (size == 20 && data[3] == 0x10) { if (size == 20 && data[3] == 0x10) {
HIDAPI_DriverXboxOne_HandleSerialIDPacket(joystick, ctx, data, size); HIDAPI_DriverXboxOne_HandleSerialIDPacket(joystick, ctx, data, size);
@ -1082,6 +1101,9 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
#endif #endif
break; break;
} }
if (!joystick) {
break;
}
HIDAPI_DriverXboxOne_HandleStatePacket(joystick, ctx, data, size); HIDAPI_DriverXboxOne_HandleStatePacket(joystick, ctx, data, size);
break; break;
default: default:
@ -1111,37 +1133,14 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
if (size < 0) { if (size < 0) {
/* Read error, device is disconnected */ /* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, joystick->instance_id); HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
} }
return (size >= 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 static void
HIDAPI_DriverXboxOne_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 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 static void
@ -1157,7 +1156,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
HIDAPI_DriverXboxOne_UnregisterHints, HIDAPI_DriverXboxOne_UnregisterHints,
HIDAPI_DriverXboxOne_IsEnabled, HIDAPI_DriverXboxOne_IsEnabled,
HIDAPI_DriverXboxOne_IsSupportedDevice, HIDAPI_DriverXboxOne_IsSupportedDevice,
HIDAPI_DriverXboxOne_GetDeviceName,
HIDAPI_DriverXboxOne_InitDevice, HIDAPI_DriverXboxOne_InitDevice,
HIDAPI_DriverXboxOne_GetDevicePlayerIndex, HIDAPI_DriverXboxOne_GetDevicePlayerIndex,
HIDAPI_DriverXboxOne_SetDevicePlayerIndex, HIDAPI_DriverXboxOne_SetDevicePlayerIndex,

View file

@ -314,6 +314,20 @@ HIDAPI_CleanupDeviceDriver(SDL_HIDAPI_Device *device)
device->driver->FreeDevice(device); device->driver->FreeDevice(device);
device->driver = NULL; 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 static void
@ -344,18 +358,27 @@ HIDAPI_SetupDeviceDriver(SDL_HIDAPI_Device *device)
return; /* Already setup */ return; /* Already setup */
} }
/* 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); 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);
}
}
/* Initialize the device, which may cause a connected event */ /* Initialize the device, which may cause a connected event */
if (device->driver && !device->driver->InitDevice(device)) { 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; 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 SDL_bool
HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID) HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID)
{ {
@ -1102,6 +1151,13 @@ HIDAPI_JoystickOpen(SDL_Joystick *joystick, int device_index)
} }
hwdata->device = device; 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)) { if (!device->driver->OpenJoystick(device, joystick)) {
/* The open failed, mark this device as disconnected and update devices */ /* The open failed, mark this device as disconnected and update devices */
HIDAPI_JoystickDisconnected(device, joystickID); HIDAPI_JoystickDisconnected(device, joystickID);

View file

@ -103,7 +103,6 @@ typedef struct _SDL_HIDAPI_DeviceDriver
void (*UnregisterHints)(SDL_HintCallback callback, void *userdata); void (*UnregisterHints)(SDL_HintCallback callback, void *userdata);
SDL_bool (*IsEnabled)(void); 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); 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); SDL_bool (*InitDevice)(SDL_HIDAPI_Device *device);
int (*GetDevicePlayerIndex)(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id); int (*GetDevicePlayerIndex)(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id);
void (*SetDevicePlayerIndex)(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index); 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 SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name);
extern void HIDAPI_UpdateDevices(void); 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 SDL_bool HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID);
extern void HIDAPI_JoystickDisconnected(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID); extern void HIDAPI_JoystickDisconnected(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID);