Atlas - SDL_hidapi_gip.c

Home / ext / SDL / src / joystick / hidapi Lines: 1 | Size: 99187 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#ifdef SDL_JOYSTICK_HIDAPI 24 25#include "../../events/SDL_keyboard_c.h" 26#include "../SDL_sysjoystick.h" 27#include "SDL_hidapijoystick_c.h" 28#include "SDL_hidapi_rumble.h" 29 30#ifdef SDL_JOYSTICK_HIDAPI_GIP 31 32// This driver is based on the Microsoft GIP spec at: 33// https://aka.ms/gipdocs 34// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gipusb/e7c90904-5e21-426e-b9ad-d82adeee0dbc 35 36// Define this if you want to log all packets from the controller 37#if 0 38#define DEBUG_XBOX_PROTOCOL 39#endif 40 41#define MAX_MESSAGE_LENGTH 0x4000 42#define MAX_ATTACHMENTS 8 43 44#define GIP_DATA_CLASS_COMMAND (0u << 5) 45#define GIP_DATA_CLASS_LOW_LATENCY (1u << 5) 46#define GIP_DATA_CLASS_STANDARD_LATENCY (2u << 5) 47#define GIP_DATA_CLASS_AUDIO (3u << 5) 48 49#define GIP_DATA_CLASS_SHIFT 5 50#define GIP_DATA_CLASS_MASK (7u << 5) 51 52/* System messages */ 53#define GIP_CMD_PROTO_CONTROL 0x01 54#define GIP_CMD_HELLO_DEVICE 0x02 55#define GIP_CMD_STATUS_DEVICE 0x03 56#define GIP_CMD_METADATA 0x04 57#define GIP_CMD_SET_DEVICE_STATE 0x05 58#define GIP_CMD_SECURITY 0x06 59#define GIP_CMD_GUIDE_BUTTON 0x07 60#define GIP_CMD_AUDIO_CONTROL 0x08 61#define GIP_CMD_LED 0x0a 62#define GIP_CMD_HID_REPORT 0x0b 63#define GIP_CMD_FIRMWARE 0x0c 64#define GIP_CMD_EXTENDED 0x1e 65#define GIP_CMD_DEBUG 0x1f 66#define GIP_AUDIO_DATA 0x60 67 68/* Navigation vendor messages */ 69#define GIP_CMD_DIRECT_MOTOR 0x09 70#define GIP_LL_INPUT_REPORT 0x20 71#define GIP_LL_OVERFLOW_INPUT_REPORT 0x26 72 73/* Wheel and ArcadeStick vendor messages */ 74#define GIP_CMD_INITIAL_REPORTS_REQUEST 0x0a 75#define GIP_LL_STATIC_CONFIGURATION 0x21 76#define GIP_LL_BUTTON_INFO_REPORT 0x22 77 78/* Wheel vendor messages */ 79#define GIP_CMD_SET_APPLICATION_MEMORY 0x0b 80#define GIP_CMD_SET_EQUATIONS_STATES 0x0c 81#define GIP_CMD_SET_EQUATION 0x0d 82 83/* FlightStick vendor messages */ 84#define GIP_CMD_DEVICE_CAPABILITIES 0x00 85#define GIP_CMD_LED_CAPABILITIES 0x01 86#define GIP_CMD_SET_LED_STATE 0x02 87 88/* Undocumented Elite 2 vendor messages */ 89#define GIP_CMD_RAW_REPORT 0x0c 90#define GIP_CMD_GUIDE_COLOR 0x0e 91#define GIP_SL_ELITE_CONFIG 0x4d 92 93#define GIP_BTN_OFFSET_XBE1 28 94#define GIP_BTN_OFFSET_XBE2 14 95 96#define GIP_FLAG_FRAGMENT (1u << 7) 97#define GIP_FLAG_INIT_FRAG (1u << 6) 98#define GIP_FLAG_SYSTEM (1u << 5) 99#define GIP_FLAG_ACME (1u << 4) 100#define GIP_FLAG_ATTACHMENT_MASK 0x7 101 102#define GIP_AUDIO_FORMAT_NULL 0 103#define GIP_AUDIO_FORMAT_8000HZ_1CH 1 104#define GIP_AUDIO_FORMAT_8000HZ_2CH 2 105#define GIP_AUDIO_FORMAT_12000HZ_1CH 3 106#define GIP_AUDIO_FORMAT_12000HZ_2CH 4 107#define GIP_AUDIO_FORMAT_16000HZ_1CH 5 108#define GIP_AUDIO_FORMAT_16000HZ_2CH 6 109#define GIP_AUDIO_FORMAT_20000HZ_1CH 7 110#define GIP_AUDIO_FORMAT_20000HZ_2CH 8 111#define GIP_AUDIO_FORMAT_24000HZ_1CH 9 112#define GIP_AUDIO_FORMAT_24000HZ_2CH 10 113#define GIP_AUDIO_FORMAT_32000HZ_1CH 11 114#define GIP_AUDIO_FORMAT_32000HZ_2CH 12 115#define GIP_AUDIO_FORMAT_40000HZ_1CH 13 116#define GIP_AUDIO_FORMAT_40000HZ_2CH 14 117#define GIP_AUDIO_FORMAT_48000HZ_1CH 15 118#define GIP_AUDIO_FORMAT_48000HZ_2CH 16 119#define GIP_AUDIO_FORMAT_48000HZ_6CH 32 120#define GIP_AUDIO_FORMAT_48000HZ_8CH 33 121 122/* Protocol Control constants */ 123#define GIP_CONTROL_CODE_ACK 0 124#define GIP_CONTROL_CODE_NACK 1 /* obsolete */ 125#define GIP_CONTROL_CODE_UNK 2 /* obsolete */ 126#define GIP_CONTROL_CODE_AB 3 /* obsolete */ 127#define GIP_CONTROL_CODE_MPER 4 /* obsolete */ 128#define GIP_CONTROL_CODE_STOP 5 /* obsolete */ 129#define GIP_CONTROL_CODE_START 6 /* obsolete */ 130#define GIP_CONTROL_CODE_ERR 7 /* obsolete */ 131 132/* Status Device constants */ 133#define GIP_POWER_LEVEL_OFF 0 134#define GIP_POWER_LEVEL_STANDBY 1 /* obsolete */ 135#define GIP_POWER_LEVEL_FULL 2 136 137#define GIP_NOT_CHARGING 0 138#define GIP_CHARGING 1 139#define GIP_CHARGE_ERROR 2 140 141#define GIP_BATTERY_ABSENT 0 142#define GIP_BATTERY_STANDARD 1 143#define GIP_BATTERY_RECHARGEABLE 2 144 145#define GIP_BATTERY_CRITICAL 0 146#define GIP_BATTERY_LOW 1 147#define GIP_BATTERY_MEDIUM 2 148#define GIP_BATTERY_FULL 3 149 150#define GIP_EVENT_FAULT 0x0002 151 152#define GIP_FAULT_UNKNOWN 0 153#define GIP_FAULT_HARD 1 154#define GIP_FAULT_NMI 2 155#define GIP_FAULT_SVC 3 156#define GIP_FAULT_PEND_SV 4 157#define GIP_FAULT_SMART_PTR 5 158#define GIP_FAULT_MCU 6 159#define GIP_FAULT_BUS 7 160#define GIP_FAULT_USAGE 8 161#define GIP_FAULT_RADIO_HANG 9 162#define GIP_FAULT_WATCHDOG 10 163#define GIP_FAULT_LINK_STALL 11 164#define GIP_FAULT_ASSERTION 12 165 166/* Metadata constants */ 167#define GIP_MESSAGE_FLAG_BIG_ENDIAN (1u << 0) 168#define GIP_MESSAGE_FLAG_RELIABLE (1u << 1) 169#define GIP_MESSAGE_FLAG_SEQUENCED (1u << 2) 170#define GIP_MESSAGE_FLAG_DOWNSTREAM (1u << 3) 171#define GIP_MESSAGE_FLAG_UPSTREAM (1u << 4) 172#define GIP_MESSAGE_FLAG_DS_REQUEST_RESPONSE (1u << 5) 173 174#define GIP_DATA_TYPE_CUSTOM 1 175#define GIP_DATA_TYPE_AUDIO 2 176#define GIP_DATA_TYPE_SECURITY 3 177#define GIP_DATA_TYPE_GIP 4 178 179/* Set Device State constants */ 180#define GIP_STATE_START 0 181#define GIP_STATE_STOP 1 182#define GIP_STATE_STANDBY 2 /* obsolete */ 183#define GIP_STATE_FULL_POWER 3 184#define GIP_STATE_OFF 4 185#define GIP_STATE_QUIESCE 5 186#define GIP_STATE_UNK6 6 187#define GIP_STATE_RESET 7 188 189/* Guide Button Status constants */ 190#define GIP_LED_GUIDE 0 191#define GIP_LID_IR 1 /* deprecated */ 192 193#define GIP_LED_GUIDE_OFF 0 194#define GIP_LED_GUIDE_ON 1 195#define GIP_LED_GUIDE_FAST_BLINK 2 196#define GIP_LED_GUIDE_SLOW_BLINK 3 197#define GIP_LED_GUIDE_CHARGING_BLINK 4 198#define GIP_LED_GUIDE_RAMP_TO_LEVEL 0xd 199 200#define GIP_LED_IR_OFF 0 201#define GIP_LED_IR_ON_100MS 1 202#define GIP_LED_IR_PATTERN 4 203 204/* Direct Motor Command constants */ 205#define GIP_MOTOR_RIGHT_VIBRATION (1u << 0) 206#define GIP_MOTOR_LEFT_VIBRATION (1u << 1) 207#define GIP_MOTOR_RIGHT_IMPULSE (1u << 2) 208#define GIP_MOTOR_LEFT_IMPULSE (1u << 3) 209#define GIP_MOTOR_ALL 0xF 210 211/* Extended Comand constants */ 212#define GIP_EXTCMD_GET_CAPABILITIES 0x00 213#define GIP_EXTCMD_GET_TELEMETRY_DATA 0x01 214#define GIP_EXTCMD_GET_SERIAL_NUMBER 0x04 215 216#define GIP_EXTENDED_STATUS_OK 0 217#define GIP_EXTENDED_STATUS_NOT_SUPPORTED 1 218#define GIP_EXTENDED_STATUS_NOT_READY 2 219#define GIP_EXTENDED_STATUS_ACCESS_DENIED 3 220#define GIP_EXTENDED_STATUS_FAILED 4 221 222/* Internal constants, not part of protocol */ 223#define GIP_HELLO_TIMEOUT 2000 224#define GIP_ACME_TIMEOUT 10 225 226#define GIP_DEFAULT_IN_SYSTEM_MESSAGES 0x5e 227#define GIP_DEFAULT_OUT_SYSTEM_MESSAGES 0x472 228 229#define GIP_FEATURE_CONSOLE_FUNCTION_MAP (1u << 0) 230#define GIP_FEATURE_CONSOLE_FUNCTION_MAP_OVERFLOW (1u << 1) 231#define GIP_FEATURE_ELITE_BUTTONS (1u << 2) 232#define GIP_FEATURE_DYNAMIC_LATENCY_INPUT (1u << 3) 233#define GIP_FEATURE_SECURITY_OPT_OUT (1u << 4) 234#define GIP_FEATURE_MOTOR_CONTROL (1u << 5) 235#define GIP_FEATURE_GUIDE_COLOR (1u << 6) 236#define GIP_FEATURE_EXTENDED_SET_DEVICE_STATE (1u << 7) 237 238#define GIP_QUIRK_NO_HELLO (1u << 0) 239#define GIP_QUIRK_BROKEN_METADATA (1u << 1) 240#define GIP_QUIRK_NO_IMPULSE_VIBRATION (1u << 2) 241 242typedef enum 243{ 244 GIP_METADATA_NONE = 0, 245 GIP_METADATA_GOT = 1, 246 GIP_METADATA_FAKED = 2, 247 GIP_METADATA_PENDING = 3, 248} GIP_MetadataStatus; 249 250#ifndef VK_LWIN 251#define VK_LWIN 0x5b 252#endif 253 254typedef enum 255{ 256 GIP_TYPE_UNKNOWN = -1, 257 GIP_TYPE_GAMEPAD = 0, 258 GIP_TYPE_ARCADE_STICK = 1, 259 GIP_TYPE_WHEEL = 2, 260 GIP_TYPE_FLIGHT_STICK = 3, 261 GIP_TYPE_NAVIGATION_CONTROLLER = 4, 262 GIP_TYPE_CHATPAD = 5, 263 GIP_TYPE_HEADSET = 6, 264} GIP_AttachmentType; 265 266typedef enum 267{ 268 GIP_RUMBLE_STATE_IDLE, 269 GIP_RUMBLE_STATE_QUEUED, 270 GIP_RUMBLE_STATE_BUSY, 271} GIP_RumbleState; 272 273typedef enum 274{ 275 GIP_BTN_FMT_UNKNOWN, 276 GIP_BTN_FMT_XBE1, 277 GIP_BTN_FMT_XBE2_RAW, 278 GIP_BTN_FMT_XBE2_4, 279 GIP_BTN_FMT_XBE2_5, 280} GIP_EliteButtonFormat; 281 282/* These come across the wire as little-endian, so let's store them in-memory as such so we can memcmp */ 283#define MAKE_GUID(NAME, A, B, C, D0, D1, D2, D3, D4, D5, D6, D7) \ 284 static const GUID NAME = { SDL_Swap32LE(A), SDL_Swap16LE(B), SDL_Swap16LE(C), { D0, D1, D2, D3, D4, D5, D6, D7 } } 285 286typedef struct GUID 287{ 288 Uint32 a; 289 Uint16 b; 290 Uint16 c; 291 Uint8 d[8]; 292} GUID; 293SDL_COMPILE_TIME_ASSERT(GUID, sizeof(GUID) == 16); 294 295MAKE_GUID(GUID_ArcadeStick, 0x332054cc, 0xa34b, 0x41d5, 0xa3, 0x4a, 0xa6, 0xa6, 0x71, 0x1e, 0xc4, 0xb3); 296MAKE_GUID(GUID_DynamicLatencyInput, 0x87f2e56b, 0xc3bb, 0x49b1, 0x82, 0x65, 0xff, 0xff, 0xf3, 0x77, 0x99, 0xee); 297MAKE_GUID(GUID_FlightStick, 0x03f1a011, 0xefe9, 0x4cc1, 0x96, 0x9c, 0x38, 0xdc, 0x55, 0xf4, 0x04, 0xd0); 298MAKE_GUID(GUID_IHeadset, 0xbc25d1a3, 0xc24e, 0x4992, 0x9d, 0xda, 0xef, 0x4f, 0x12, 0x3e, 0xf5, 0xdc); 299MAKE_GUID(GUID_IConsoleFunctionMap_InputReport, 0xecddd2fe, 0xd387, 0x4294, 0xbd, 0x96, 0x1a, 0x71, 0x2e, 0x3d, 0xc7, 0x7d); 300MAKE_GUID(GUID_IConsoleFunctionMap_OverflowInputReport, 0x137d4bd0, 0x9347, 0x4472, 0xaa, 0x26, 0x8c, 0x34, 0xa0, 0x8f, 0xf9, 0xbd); 301MAKE_GUID(GUID_IController, 0x9776ff56, 0x9bfd, 0x4581, 0xad, 0x45, 0xb6, 0x45, 0xbb, 0xa5, 0x26, 0xd6); 302MAKE_GUID(GUID_IDevAuthPCOptOut, 0x7a34ce77, 0x7de2, 0x45c6, 0x8c, 0xa4, 0x00, 0x42, 0xc0, 0x8b, 0xd9, 0x4a); 303MAKE_GUID(GUID_IEliteButtons, 0x37d19ff7, 0xb5c6, 0x49d1, 0xa7, 0x5e, 0x03, 0xb2, 0x4b, 0xef, 0x8c, 0x89); 304MAKE_GUID(GUID_IGamepad, 0x082e402c, 0x07df, 0x45e1, 0xa5, 0xab, 0xa3, 0x12, 0x7a, 0xf1, 0x97, 0xb5); 305MAKE_GUID(GUID_NavigationController, 0xb8f31fe7, 0x7386, 0x40e9, 0xa9, 0xf8, 0x2f, 0x21, 0x26, 0x3a, 0xcf, 0xb7); 306MAKE_GUID(GUID_Wheel, 0x646979cf, 0x6b71, 0x4e96, 0x8d, 0xf9, 0x59, 0xe3, 0x98, 0xd7, 0x42, 0x0c); 307 308/* 309 * The following GUIDs are observed, but the exact meanings aren't known, so 310 * for now we document them but don't use them anywhere. 311 * 312 * MAKE_GUID(GUID_GamepadEmu, 0xe2e5f1bc, 0xa6e6, 0x41a2, 0x8f, 0x43, 0x33, 0xcf, 0xa2, 0x51, 0x09, 0x81); 313 * MAKE_GUID(GUID_IAudioOnly, 0x92844cd1, 0xf7c8, 0x49ef, 0x97, 0x77, 0x46, 0x7d, 0xa7, 0x08, 0xad, 0x10); 314 * MAKE_GUID(GUID_IControllerProfileModeState, 0xf758dc66, 0x022c, 0x48b8, 0xa4, 0xf6, 0x45, 0x7b, 0xa8, 0x0e, 0x2a, 0x5b); 315 * MAKE_GUID(GUID_ICustomAudio, 0x63fd9cc9, 0x94ee, 0x4b5d, 0x9c, 0x4d, 0x8b, 0x86, 0x4c, 0x14, 0x9c, 0xac); 316 * MAKE_GUID(GUID_IExtendedDeviceFlags, 0x34ad9b1e, 0x36ad, 0x4fb5, 0x8a, 0xc7, 0x17, 0x23, 0x4c, 0x9f, 0x54, 0x6f); 317 * MAKE_GUID(GUID_IProgrammableGamepad, 0x31c1034d, 0xb5b7, 0x4551, 0x98, 0x13, 0x87, 0x69, 0xd4, 0xa0, 0xe4, 0xf9); 318 * MAKE_GUID(GUID_IVirtualDevice, 0xdfd26825, 0x110a, 0x4e94, 0xb9, 0x37, 0xb2, 0x7c, 0xe4, 0x7b, 0x25, 0x40); 319 * MAKE_GUID(GUID_OnlineDevAuth, 0x632b1fd1, 0xa3e9, 0x44f9, 0x84, 0x20, 0x5c, 0xe3, 0x44, 0xa0, 0x64, 0x04); 320 * 321 * Seen on Elite Controller, Adaptive Controller: 9ebd00a3-b5e6-4c08-a33b-673126459ec4 322 * Seen on Adaptive Controller: ce1e58c5-221c-4bdb-9c24-bf3941601320 323 * Seen on Elite 2 Controller: f758dc66-022c-48b8-a4f6-457ba80e2a5b (IControllerProfileModeState) 324 * Seen on Elite 2 Controller: 31c1034d-b5b7-4551-9813-8769d4a0e4f9 (IProgrammableGamepad) 325 * Seen on Elite 2 Controller: 34ad9b1e-36ad-4fb5-8ac7-17234c9f546f (IExtendedDeviceFlags) 326 * Seen on Elite 2 Controller: 88e0b694-6bd9-4416-a560-e7fafdfa528f 327 * Seen on Elite 2 Controller: ea96c8c0-b216-448b-be80-7e5deb0698e2 328 */ 329 330static const int GIP_DataClassMtu[8] = { 64, 64, 64, 2048, 0, 0, 0, 0 }; 331 332typedef struct GIP_Quirks 333{ 334 Uint16 vendor_id; 335 Uint16 product_id; 336 Uint8 attachment_index; 337 Uint32 added_features; 338 Uint32 filtered_features; 339 Uint32 quirks; 340 Uint32 extra_in_system[8]; 341 Uint32 extra_out_system[8]; 342 GIP_AttachmentType device_type; 343 Uint8 extra_buttons; 344 Uint8 extra_axes; 345} GIP_Quirks; 346 347static const GIP_Quirks quirks[] = { 348 { USB_VENDOR_MICROSOFT, USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1, 0, 349 .added_features = GIP_FEATURE_ELITE_BUTTONS, 350 .filtered_features = GIP_FEATURE_CONSOLE_FUNCTION_MAP }, 351 352 { USB_VENDOR_MICROSOFT, USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2, 0, 353 .added_features = GIP_FEATURE_ELITE_BUTTONS | GIP_FEATURE_DYNAMIC_LATENCY_INPUT | GIP_FEATURE_CONSOLE_FUNCTION_MAP | GIP_FEATURE_GUIDE_COLOR | GIP_FEATURE_EXTENDED_SET_DEVICE_STATE, 354 .extra_in_system = { 1 << GIP_CMD_FIRMWARE }, 355 .extra_out_system = { 1 << GIP_CMD_FIRMWARE } }, 356 357 { USB_VENDOR_MICROSOFT, USB_PRODUCT_XBOX_SERIES_X, 0, 358 .added_features = GIP_FEATURE_DYNAMIC_LATENCY_INPUT }, 359 360 { USB_VENDOR_PDP, USB_PRODUCT_PDP_ROCK_CANDY, 0, 361 .quirks = GIP_QUIRK_NO_HELLO }, 362 363 { USB_VENDOR_POWERA, USB_PRODUCT_BDA_XB1_FIGHTPAD, 0, 364 .filtered_features = GIP_FEATURE_MOTOR_CONTROL }, 365 366 { USB_VENDOR_POWERA, USB_PRODUCT_BDA_XB1_CLASSIC, 0, 367 .quirks = GIP_QUIRK_NO_IMPULSE_VIBRATION }, 368 369 { USB_VENDOR_POWERA, USB_PRODUCT_BDA_XB1_SPECTRA_PRO, 0, 370 .quirks = GIP_QUIRK_NO_IMPULSE_VIBRATION }, 371 372 { USB_VENDOR_RAZER, USB_PRODUCT_RAZER_ATROX, 0, 373 .filtered_features = GIP_FEATURE_MOTOR_CONTROL, 374 .device_type = GIP_TYPE_ARCADE_STICK }, 375 376 { USB_VENDOR_THRUSTMASTER, USB_PRODUCT_THRUSTMASTER_T_FLIGHT_HOTAS_ONE, 0, 377 .filtered_features = GIP_FEATURE_MOTOR_CONTROL, 378 .device_type = GIP_TYPE_FLIGHT_STICK, 379 .extra_buttons = 5, 380 .extra_axes = 3 }, 381 382 {0}, 383}; 384 385typedef struct GIP_Header 386{ 387 Uint8 message_type; 388 Uint8 flags; 389 Uint8 sequence_id; 390 Uint64 length; 391} GIP_Header; 392 393typedef struct GIP_AudioFormat 394{ 395 Uint8 inbound; 396 Uint8 outbound; 397} GIP_AudioFormat; 398 399typedef struct GIP_DeviceMetadata 400{ 401 Uint8 num_audio_formats; 402 Uint8 num_preferred_types; 403 Uint8 num_supported_interfaces; 404 Uint8 hid_descriptor_size; 405 406 Uint32 in_system_messages[8]; 407 Uint32 out_system_messages[8]; 408 409 GIP_AudioFormat *audio_formats; 410 char **preferred_types; 411 GUID *supported_interfaces; 412 Uint8 *hid_descriptor; 413 414 GIP_AttachmentType device_type; 415} GIP_DeviceMetadata; 416 417typedef struct GIP_MessageMetadata 418{ 419 Uint8 type; 420 Uint16 length; 421 Uint16 data_type; 422 Uint32 flags; 423 Uint16 period; 424 Uint16 persistence_timeout; 425} GIP_MessageMetadata; 426 427typedef struct GIP_Metadata 428{ 429 Uint16 version_major; 430 Uint16 version_minor; 431 432 GIP_DeviceMetadata device; 433 434 Uint8 num_messages; 435 GIP_MessageMetadata *message_metadata; 436} GIP_Metadata; 437 438struct GIP_Device; 439typedef struct GIP_Attachment 440{ 441 struct GIP_Device *device; 442 Uint8 attachment_index; 443 SDL_JoystickID joystick; 444 SDL_KeyboardID keyboard; 445 446 Uint8 fragment_message; 447 Uint16 total_length; 448 Uint8 *fragment_data; 449 Uint32 fragment_offset; 450 Uint64 fragment_timer; 451 int fragment_retries; 452 453 Uint16 firmware_major_version; 454 Uint16 firmware_minor_version; 455 456 GIP_MetadataStatus got_metadata; 457 Uint64 metadata_next; 458 int metadata_retries; 459 GIP_Metadata metadata; 460 461 Uint8 seq_system; 462 Uint8 seq_security; 463 Uint8 seq_extended; 464 Uint8 seq_audio; 465 Uint8 seq_vendor; 466 467 int device_state; 468 469 GIP_RumbleState rumble_state; 470 Uint64 rumble_time; 471 bool rumble_pending; 472 Uint8 left_impulse_level; 473 Uint8 right_impulse_level; 474 Uint8 left_vibration_level; 475 Uint8 right_vibration_level; 476 477 Uint8 last_input[64]; 478 479 Uint8 last_modifiers; 480 bool capslock; 481 SDL_Keycode last_key; 482 Uint32 altcode; 483 int altcode_digit; 484 485 GIP_AttachmentType attachment_type; 486 GIP_EliteButtonFormat xbe_format; 487 Uint32 features; 488 Uint32 quirks; 489 Uint8 share_button_idx; 490 Uint8 paddle_idx; 491 492 Uint8 extra_button_idx; 493 int extra_buttons; 494 int extra_axes; 495} GIP_Attachment; 496 497typedef struct GIP_Device 498{ 499 SDL_HIDAPI_Device *device; 500 501 Uint64 hello_deadline; 502 bool got_hello; 503 bool reset_for_metadata; 504 int timeout; 505 506 GIP_Attachment *attachments[MAX_ATTACHMENTS]; 507} GIP_Device; 508 509typedef struct GIP_HelloDevice 510{ 511 Uint64 device_id; 512 Uint16 vendor_id; 513 Uint16 product_id; 514 Uint16 firmware_major_version; 515 Uint16 firmware_minor_version; 516 Uint16 firmware_build_version; 517 Uint16 firmware_revision; 518 Uint8 hardware_major_version; 519 Uint8 hardware_minor_version; 520 Uint8 rf_proto_major_version; 521 Uint8 rf_proto_minor_version; 522 Uint8 security_major_version; 523 Uint8 security_minor_version; 524 Uint8 gip_major_version; 525 Uint8 gip_minor_version; 526} GIP_HelloDevice; 527 528typedef struct GIP_Status 529{ 530 int power_level; 531 int charge; 532 int battery_type; 533 int battery_level; 534} GIP_Status; 535 536typedef struct GIP_StatusEvent 537{ 538 Uint16 event_type; 539 Uint32 fault_tag; 540 Uint32 fault_address; 541} GIP_StatusEvent; 542 543typedef struct GIP_ExtendedStatus 544{ 545 GIP_Status base; 546 bool device_active; 547 548 int num_events; 549 GIP_StatusEvent events[5]; 550} GIP_ExtendedStatus; 551 552typedef struct GIP_DirectMotor 553{ 554 Uint8 motor_bitmap; 555 Uint8 left_impulse_level; 556 Uint8 right_impulse_level; 557 Uint8 left_vibration_level; 558 Uint8 right_vibration_level; 559 Uint8 duration; 560 Uint8 delay; 561 Uint8 repeat; 562} GIP_DirectMotor; 563 564typedef struct GIP_InitialReportsRequest 565{ 566 Uint8 type; 567 Uint8 data[2]; 568} GIP_InitialReportsRequest; 569 570static bool GIP_SetMetadataDefaults(GIP_Attachment *attachment); 571 572static int GIP_DecodeLength(Uint64 *length, const Uint8 *bytes, int num_bytes) 573{ 574 *length = 0; 575 int offset; 576 577 for (offset = 0; offset < num_bytes; offset++) { 578 Uint8 byte = bytes[offset]; 579 *length |= (byte & 0x7full) << (offset * 7); 580 if (!(byte & 0x80)) { 581 offset++; 582 break; 583 } 584 } 585 return offset; 586} 587 588static int GIP_EncodeLength(Uint64 length, Uint8 *bytes, int num_bytes) 589{ 590 int offset; 591 592 for (offset = 0; offset < num_bytes; offset++) { 593 Uint8 byte = length & 0x7f; 594 length >>= 7; 595 if (length) { 596 byte |= 0x80; 597 } 598 bytes[offset] = byte; 599 if (!length) { 600 offset++; 601 break; 602 } 603 } 604 return offset; 605} 606 607static bool GIP_SupportsSystemMessage(GIP_Attachment *attachment, Uint8 command, bool upstream) 608{ 609 if (upstream) { 610 return attachment->metadata.device.in_system_messages[command >> 5] & (1u << command); 611 } else { 612 return attachment->metadata.device.out_system_messages[command >> 5] & (1u << command); 613 } 614} 615 616static bool GIP_SupportsVendorMessage(GIP_Attachment *attachment, Uint8 command, bool upstream) 617{ 618 size_t i; 619 for (i = 0; i < attachment->metadata.num_messages; i++) { 620 GIP_MessageMetadata *metadata = &attachment->metadata.message_metadata[i]; 621 if (metadata->type != command) { 622 continue; 623 } 624 if (metadata->flags & GIP_MESSAGE_FLAG_DS_REQUEST_RESPONSE) { 625 return true; 626 } 627 if (upstream) { 628 return metadata->flags & GIP_MESSAGE_FLAG_UPSTREAM; 629 } else { 630 return metadata->flags & GIP_MESSAGE_FLAG_DOWNSTREAM; 631 } 632 } 633 return false; 634} 635 636static Uint8 GIP_SequenceNext(GIP_Attachment *attachment, Uint8 command, bool system) 637{ 638 Uint8 seq; 639 640 if (system) { 641 switch (command) { 642 case GIP_CMD_SECURITY: 643 seq = attachment->seq_security++; 644 if (!seq) { 645 seq = attachment->seq_security++; 646 } 647 break; 648 case GIP_CMD_EXTENDED: 649 seq = attachment->seq_extended++; 650 if (!seq) { 651 seq = attachment->seq_extended++; 652 } 653 break; 654 case GIP_AUDIO_DATA: 655 seq = attachment->seq_audio++; 656 if (!seq) { 657 seq = attachment->seq_audio++; 658 } 659 break; 660 default: 661 seq = attachment->seq_system++; 662 if (!seq) { 663 seq = attachment->seq_system++; 664 } 665 break; 666 } 667 } else { 668 if (command == GIP_CMD_DIRECT_MOTOR) { 669 // The motor sequence number is optional and always works with 0 670 return 0; 671 } 672 673 seq = attachment->seq_vendor++; 674 if (!seq) { 675 seq = attachment->seq_vendor++; 676 } 677 } 678 return seq; 679} 680 681static void GIP_HandleQuirks(GIP_Attachment *attachment) 682{ 683 size_t i, j; 684 for (i = 0; quirks[i].vendor_id; i++) { 685 if (quirks[i].vendor_id != attachment->device->device->vendor_id) { 686 continue; 687 } 688 if (quirks[i].product_id != attachment->device->device->product_id) { 689 continue; 690 } 691 if (quirks[i].attachment_index != attachment->attachment_index) { 692 continue; 693 } 694 attachment->features |= quirks[i].added_features; 695 attachment->features &= ~quirks[i].filtered_features; 696 attachment->quirks = quirks[i].quirks; 697 attachment->attachment_type = quirks[i].device_type; 698 699 for (j = 0; j < 8; ++j) { 700 attachment->metadata.device.in_system_messages[j] |= quirks[i].extra_in_system[j]; 701 attachment->metadata.device.out_system_messages[j] |= quirks[i].extra_out_system[j]; 702 } 703 704 attachment->extra_buttons = quirks[i].extra_buttons; 705 attachment->extra_axes = quirks[i].extra_axes; 706 break; 707 } 708} 709 710static bool GIP_SendRawMessage( 711 GIP_Device *device, 712 Uint8 message_type, 713 Uint8 flags, 714 Uint8 seq, 715 const Uint8 *bytes, 716 int num_bytes, 717 bool async, 718 SDL_HIDAPI_RumbleSentCallback callback, 719 void *userdata) 720{ 721 Uint8 buffer[2054] = { message_type, flags, seq }; 722 int offset = 3; 723 724 if (num_bytes < 0) { 725 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "GIP: Invalid message length %d", num_bytes); 726 return false; 727 } 728 729 if (num_bytes > GIP_DataClassMtu[message_type >> GIP_DATA_CLASS_SHIFT]) { 730 SDL_LogError(SDL_LOG_CATEGORY_INPUT, 731 "Attempted to send a message that requires fragmenting, which is not yet supported."); 732 return false; 733 } 734 735 offset += GIP_EncodeLength(num_bytes, &buffer[offset], sizeof(buffer) - offset); 736 737 if (num_bytes > 0) { 738 SDL_memcpy(&buffer[offset], bytes, num_bytes); 739 } 740 num_bytes += offset; 741#ifdef DEBUG_XBOX_PROTOCOL 742 HIDAPI_DumpPacket("GIP sending message: size = %d", buffer, num_bytes); 743#endif 744 745 if (async) { 746 if (!SDL_HIDAPI_LockRumble()) { 747 return false; 748 } 749 750 return SDL_HIDAPI_SendRumbleWithCallbackAndUnlock(device->device, buffer, num_bytes, callback, userdata) == num_bytes; 751 } else { 752 return SDL_hid_write(device->device->dev, buffer, num_bytes) == num_bytes; 753 } 754} 755 756static bool GIP_SendSystemMessage( 757 GIP_Attachment *attachment, 758 Uint8 message_type, 759 Uint8 flags, 760 const Uint8 *bytes, 761 int num_bytes) 762{ 763 return GIP_SendRawMessage(attachment->device, 764 message_type, 765 GIP_FLAG_SYSTEM | attachment->attachment_index | flags, 766 GIP_SequenceNext(attachment, message_type, true), 767 bytes, 768 num_bytes, 769 false, 770 NULL, 771 NULL); 772} 773 774static bool GIP_SendVendorMessage( 775 GIP_Attachment *attachment, 776 Uint8 message_type, 777 Uint8 flags, 778 const Uint8 *bytes, 779 int num_bytes) 780{ 781 return GIP_SendRawMessage(attachment->device, 782 message_type, 783 flags, 784 GIP_SequenceNext(attachment, message_type, false), 785 bytes, 786 num_bytes, 787 true, 788 NULL, 789 NULL); 790} 791 792static bool GIP_AttachmentIsController(GIP_Attachment *attachment) 793{ 794 return attachment->attachment_type != GIP_TYPE_CHATPAD && 795 attachment->attachment_type != GIP_TYPE_HEADSET; 796} 797 798static void GIP_MetadataFree(GIP_Metadata *metadata) 799{ 800 SDL_free(metadata->device.audio_formats); 801 if (metadata->device.preferred_types) { 802 int i; 803 for (i = 0; i < metadata->device.num_preferred_types; i++) { 804 SDL_free(metadata->device.preferred_types[i]); 805 } 806 SDL_free(metadata->device.preferred_types); 807 } 808 SDL_free(metadata->device.supported_interfaces); 809 SDL_free(metadata->device.hid_descriptor); 810 811 SDL_free(metadata->message_metadata); 812 SDL_memset(metadata, 0, sizeof(*metadata)); 813} 814 815static bool GIP_ParseDeviceMetadata(GIP_Metadata *metadata, const Uint8 *bytes, int num_bytes, int *offset) 816{ 817 GIP_DeviceMetadata *device = &metadata->device; 818 int buffer_offset; 819 int count; 820 int length; 821 int i; 822 823 bytes = &bytes[*offset]; 824 num_bytes -= *offset; 825 if (num_bytes < 16) { 826 return false; 827 } 828 829 length = bytes[0]; 830 length |= bytes[1] << 8; 831 if (num_bytes < length) { 832 return false; 833 } 834 835 /* Skip supported firmware versions for now */ 836 837 buffer_offset = bytes[4]; 838 buffer_offset |= bytes[5] << 8; 839 if (buffer_offset >= length) { 840 return false; 841 } 842 if (buffer_offset > 0) { 843 device->num_audio_formats = bytes[buffer_offset]; 844 if (buffer_offset + device->num_audio_formats + 1 > length) { 845 return false; 846 } 847 device->audio_formats = SDL_malloc(device->num_audio_formats); 848 SDL_memcpy(device->audio_formats, &bytes[buffer_offset + 1], device->num_audio_formats); 849 } 850 851 buffer_offset = bytes[6]; 852 buffer_offset |= bytes[7] << 8; 853 if (buffer_offset >= length) { 854 return false; 855 } 856 if (buffer_offset > 0) { 857 count = bytes[buffer_offset]; 858 if (buffer_offset + count + 1 > length) { 859 return false; 860 } 861 862 for (i = 0; i < count; i++) { 863 Uint8 message = bytes[buffer_offset + 1 + i]; 864#ifdef DEBUG_XBOX_PROTOCOL 865 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 866 "GIP: Supported upstream system message %02x", 867 message); 868#endif 869 device->in_system_messages[message >> 5] |= 1u << (message & 0x1F); 870 } 871 } 872 873 buffer_offset = bytes[8]; 874 buffer_offset |= bytes[9] << 8; 875 if (buffer_offset >= length) { 876 return false; 877 } 878 if (buffer_offset > 0) { 879 count = bytes[buffer_offset]; 880 if (buffer_offset + count + 1 > length) { 881 return false; 882 } 883 884 for (i = 0; i < count; i++) { 885 Uint8 message = bytes[buffer_offset + 1 + i]; 886#ifdef DEBUG_XBOX_PROTOCOL 887 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 888 "GIP: Supported downstream system message %02x", 889 message); 890#endif 891 device->out_system_messages[message >> 5] |= 1u << (message & 0x1F); 892 } 893 } 894 895 buffer_offset = bytes[10]; 896 buffer_offset |= bytes[11] << 8; 897 if (buffer_offset >= length) { 898 return false; 899 } 900 if (buffer_offset > 0) { 901 device->num_preferred_types = bytes[buffer_offset]; 902 device->preferred_types = SDL_calloc(device->num_preferred_types, sizeof(char *)); 903 buffer_offset++; 904 for (i = 0; i < device->num_preferred_types; i++) { 905 if (buffer_offset + 2 >= length) { 906 return false; 907 } 908 909 count = bytes[buffer_offset]; 910 count |= bytes[buffer_offset]; 911 buffer_offset += 2; 912 if (buffer_offset + count > length) { 913 return false; 914 } 915 916 device->preferred_types[i] = SDL_calloc(count + 1, sizeof(char)); 917 SDL_memcpy(device->preferred_types[i], &bytes[buffer_offset], count); 918 buffer_offset += count; 919 } 920 } 921 922 buffer_offset = bytes[12]; 923 buffer_offset |= bytes[13] << 8; 924 if (buffer_offset >= length) { 925 return false; 926 } 927 if (buffer_offset > 0) { 928 device->num_supported_interfaces = bytes[buffer_offset]; 929 if (buffer_offset + 1 + (Sint32) (device->num_supported_interfaces * sizeof(GUID)) > length) { 930 return false; 931 } 932 device->supported_interfaces = SDL_calloc(device->num_supported_interfaces, sizeof(GUID)); 933 SDL_memcpy(device->supported_interfaces, 934 &bytes[buffer_offset + 1], 935 sizeof(GUID) * device->num_supported_interfaces); 936 } 937 938 if (metadata->version_major > 1 || metadata->version_minor >= 1) { 939 /* HID descriptor support added in metadata version 1.1 */ 940 buffer_offset = bytes[14]; 941 buffer_offset |= bytes[15] << 8; 942 if (buffer_offset >= length) { 943 return false; 944 } 945 if (buffer_offset > 0) { 946 device->hid_descriptor_size = bytes[buffer_offset]; 947 if (buffer_offset + 1 + device->hid_descriptor_size > length) { 948 return false; 949 } 950 device->hid_descriptor = SDL_malloc(device->hid_descriptor_size); 951 SDL_memcpy(device->hid_descriptor, &bytes[buffer_offset + 1], device->hid_descriptor_size); 952#ifdef DEBUG_XBOX_PROTOCOL 953 HIDAPI_DumpPacket("GIP received HID descriptor: size = %d", device->hid_descriptor, device->hid_descriptor_size); 954#endif 955 } 956 } 957 958 *offset += length; 959 return true; 960} 961 962static bool GIP_ParseMessageMetadata(GIP_MessageMetadata *metadata, const Uint8 *bytes, int num_bytes, int *offset) 963{ 964 Uint16 length; 965 966 bytes = &bytes[*offset]; 967 num_bytes -= *offset; 968 969 if (num_bytes < 2) { 970 return false; 971 } 972 length = bytes[0]; 973 length |= bytes[1] << 8; 974 if (num_bytes < length) { 975 return false; 976 } 977 978 if (length < 15) { 979 return false; 980 } 981 982 metadata->type = bytes[2]; 983 metadata->length = bytes[3]; 984 metadata->length |= bytes[4] << 8; 985 metadata->data_type = bytes[5]; 986 metadata->data_type |= bytes[6] << 8; 987 metadata->flags = bytes[7]; 988 metadata->flags |= bytes[8] << 8; 989 metadata->flags |= bytes[9] << 16; 990 metadata->flags |= bytes[10] << 24; 991 metadata->period = bytes[11]; 992 metadata->period |= bytes[12] << 8; 993 metadata->persistence_timeout = bytes[13]; 994 metadata->persistence_timeout |= bytes[14] << 8; 995 996#ifdef DEBUG_XBOX_PROTOCOL 997 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 998 "GIP: Supported vendor message type %02x of length %d, %s, %s, %s", 999 metadata->type, 1000 metadata->length, 1001 metadata->flags & GIP_MESSAGE_FLAG_UPSTREAM ? 1002 (metadata->flags & GIP_MESSAGE_FLAG_DOWNSTREAM ? "bidirectional" : "upstream") : 1003 metadata->flags & GIP_MESSAGE_FLAG_DOWNSTREAM ? "downstream" : 1004 metadata->flags & GIP_MESSAGE_FLAG_DS_REQUEST_RESPONSE ? "downstream request response" : 1005 "unknown direction", 1006 metadata->flags & GIP_MESSAGE_FLAG_SEQUENCED ? "sequenced" : "not sequenced", 1007 metadata->flags & GIP_MESSAGE_FLAG_RELIABLE ? "reliable" : "unreliable"); 1008#endif 1009 1010 *offset += length; 1011 return true; 1012} 1013 1014static bool GIP_ParseMetadata(GIP_Metadata *metadata, const Uint8 *bytes, int num_bytes) 1015{ 1016 int header_size; 1017 int metadata_size; 1018 int offset = 0; 1019 int i; 1020 1021 if (num_bytes < 16) { 1022 return false; 1023 } 1024 1025#ifdef DEBUG_XBOX_PROTOCOL 1026 HIDAPI_DumpPacket("GIP received metadata: size = %d", bytes, num_bytes); 1027#endif 1028 1029 header_size = bytes[0]; 1030 header_size |= bytes[1] << 8; 1031 if (num_bytes < header_size || header_size < 16) { 1032 return false; 1033 } 1034 metadata->version_major = bytes[2]; 1035 metadata->version_major |= bytes[3] << 8; 1036 metadata->version_minor = bytes[4]; 1037 metadata->version_minor |= bytes[5] << 8; 1038 /* Middle bytes are reserved */ 1039 metadata_size = bytes[14]; 1040 metadata_size |= bytes[15] << 8; 1041 1042 if (num_bytes < metadata_size || metadata_size < header_size) { 1043 return false; 1044 } 1045 offset = header_size; 1046 1047 if (!GIP_ParseDeviceMetadata(metadata, bytes, num_bytes, &offset)) { 1048 goto err; 1049 } 1050 1051 if (offset >= num_bytes) { 1052 goto err; 1053 } 1054 metadata->num_messages = bytes[offset]; 1055 offset++; 1056 if (metadata->num_messages > 0) { 1057 metadata->message_metadata = SDL_calloc(metadata->num_messages, sizeof(*metadata->message_metadata)); 1058 for (i = 0; i < metadata->num_messages; i++) { 1059 if (!GIP_ParseMessageMetadata(&metadata->message_metadata[i], bytes, num_bytes, &offset)) { 1060 goto err; 1061 } 1062 } 1063 } 1064 1065 return true; 1066 1067err: 1068 GIP_MetadataFree(metadata); 1069 return false; 1070} 1071 1072static bool GIP_Acknowledge( 1073 GIP_Device *device, 1074 const GIP_Header *header, 1075 Uint32 fragment_offset, 1076 Uint16 bytes_remaining) 1077{ 1078 Uint8 buffer[] = { 1079 GIP_CONTROL_CODE_ACK, 1080 header->message_type, 1081 header->flags & GIP_FLAG_SYSTEM, 1082 (Uint8) fragment_offset, 1083 (Uint8) (fragment_offset >> 8), 1084 (Uint8) (fragment_offset >> 16), 1085 fragment_offset >> 24, 1086 (Uint8) bytes_remaining, 1087 bytes_remaining >> 8, 1088 }; 1089 1090 return GIP_SendRawMessage(device, 1091 GIP_CMD_PROTO_CONTROL, 1092 GIP_FLAG_SYSTEM | (header->flags & GIP_FLAG_ATTACHMENT_MASK), 1093 header->sequence_id, 1094 buffer, 1095 sizeof(buffer), 1096 false, 1097 NULL, 1098 NULL); 1099} 1100 1101static bool GIP_FragmentFailed(GIP_Attachment *attachment, const GIP_Header *header) 1102{ 1103 attachment->fragment_retries++; 1104 if (attachment->fragment_retries > 8) { 1105 if (attachment->fragment_data) { 1106 SDL_free(attachment->fragment_data); 1107 attachment->fragment_data = NULL; 1108 } 1109 attachment->fragment_message = 0; 1110 } 1111 return GIP_Acknowledge(attachment->device, 1112 header, 1113 attachment->fragment_offset, 1114 (Uint16) (attachment->total_length - attachment->fragment_offset)); 1115} 1116 1117static bool GIP_EnableEliteButtons(GIP_Attachment *attachment) { 1118 if (attachment->device->device->vendor_id == USB_VENDOR_MICROSOFT) { 1119 if (attachment->device->device->product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1) { 1120 attachment->xbe_format = GIP_BTN_FMT_XBE1; 1121 } else if (attachment->device->device->product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2) { 1122 if (attachment->firmware_major_version == 4) { 1123 attachment->xbe_format = GIP_BTN_FMT_XBE2_4; 1124 } else if (attachment->firmware_major_version == 5) { 1125 /* 1126 * The exact range for this being necessary is unknown, but it 1127 * starts at 5.11 and at either 5.16 or 5.17. This approach 1128 * still works on 5.21, even if it's not necessary, so having 1129 * a loose upper limit is fine. 1130 */ 1131 if (attachment->firmware_minor_version >= 11 && 1132 attachment->firmware_minor_version < 17) 1133 { 1134 attachment->xbe_format = GIP_BTN_FMT_XBE2_RAW; 1135 } else { 1136 attachment->xbe_format = GIP_BTN_FMT_XBE2_5; 1137 } 1138 } 1139 } 1140 } 1141 if (attachment->xbe_format == GIP_BTN_FMT_XBE2_RAW) { 1142 /* 1143 * The meaning of this packet is unknown and not documented, but it's 1144 * needed for the Elite 2 controller to send raw reports 1145 */ 1146 static const Uint8 enable_raw_report[] = { 7, 0 }; 1147 1148 return GIP_SendVendorMessage(attachment, 1149 GIP_SL_ELITE_CONFIG, 1150 0, 1151 enable_raw_report, 1152 sizeof(enable_raw_report)); 1153 } 1154 1155 return true; 1156} 1157 1158static bool GIP_SendGuideButtonLED(GIP_Attachment *attachment, Uint8 pattern, Uint8 intensity) 1159{ 1160 Uint8 buffer[] = { 1161 GIP_LED_GUIDE, 1162 pattern, 1163 intensity, 1164 }; 1165 1166 if (!GIP_SupportsSystemMessage(attachment, GIP_CMD_LED, false)) { 1167 return true; 1168 } 1169 return GIP_SendSystemMessage(attachment, GIP_CMD_LED, 0, buffer, sizeof(buffer)); 1170} 1171 1172static bool GIP_SendQueryFirmware(GIP_Attachment *attachment, Uint8 slot) 1173{ 1174 /* The "slot" variable might not be correct; the packet format is still unclear */ 1175 Uint8 buffer[] = { 0x1, slot, 0, 0, 0 }; 1176 1177 return GIP_SendSystemMessage(attachment, GIP_CMD_FIRMWARE, 0, buffer, sizeof(buffer)); 1178} 1179 1180static bool GIP_SendSetDeviceState(GIP_Attachment *attachment, Uint8 state) 1181{ 1182 Uint8 buffer[] = { state }; 1183 return GIP_SendSystemMessage(attachment, 1184 GIP_CMD_SET_DEVICE_STATE, 1185 attachment->attachment_index, 1186 buffer, 1187 sizeof(buffer)); 1188} 1189 1190static bool GIP_SendInitSequence(GIP_Attachment *attachment) 1191{ 1192 if (attachment->features & GIP_FEATURE_EXTENDED_SET_DEVICE_STATE) { 1193 /* 1194 * The meaning of this packet is unknown and not documented, but it's 1195 * needed for the Elite 2 controller to start up on older firmwares 1196 */ 1197 static const Uint8 set_device_state[] = { GIP_STATE_UNK6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x55, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; 1198 1199 if (!GIP_SendSystemMessage(attachment, 1200 GIP_CMD_SET_DEVICE_STATE, 1201 0, 1202 set_device_state, 1203 sizeof(set_device_state))) 1204 { 1205 return false; 1206 } 1207 } 1208 if (!GIP_EnableEliteButtons(attachment)) { 1209 return false; 1210 } 1211 if (!GIP_SendSetDeviceState(attachment, GIP_STATE_START)) { 1212 return false; 1213 } 1214 attachment->device_state = GIP_STATE_START; 1215 1216 if (!GIP_SendGuideButtonLED(attachment, GIP_LED_GUIDE_ON, 20)) { 1217 return false; 1218 } 1219 1220 if (GIP_SupportsSystemMessage(attachment, GIP_CMD_SECURITY, false) && 1221 !(attachment->features & GIP_FEATURE_SECURITY_OPT_OUT)) 1222 { 1223 /* TODO: Implement Security command property */ 1224 Uint8 buffer[] = { 0x1, 0x0 }; 1225 GIP_SendSystemMessage(attachment, GIP_CMD_SECURITY, 0, buffer, sizeof(buffer)); 1226 } 1227 1228 if (GIP_SupportsVendorMessage(attachment, GIP_CMD_INITIAL_REPORTS_REQUEST, false)) { 1229 GIP_InitialReportsRequest request = { 0 }; 1230 GIP_SendVendorMessage(attachment, GIP_CMD_INITIAL_REPORTS_REQUEST, 0, (const Uint8 *)&request, sizeof(request)); 1231 } 1232 1233 if (GIP_SupportsVendorMessage(attachment, GIP_CMD_DEVICE_CAPABILITIES, false)) { 1234 GIP_SendVendorMessage(attachment, GIP_CMD_DEVICE_CAPABILITIES, 0, NULL, 0); 1235 } 1236 1237 if ((!attachment->attachment_index || GIP_AttachmentIsController(attachment)) && !attachment->joystick) { 1238 return HIDAPI_JoystickConnected(attachment->device->device, &attachment->joystick); 1239 } 1240 if (attachment->attachment_type == GIP_TYPE_CHATPAD && !attachment->keyboard) { 1241 attachment->keyboard = (SDL_KeyboardID)(uintptr_t) attachment; 1242 SDL_AddKeyboard(attachment->keyboard, "Xbox One Chatpad"); 1243 } 1244 return true; 1245} 1246 1247static bool GIP_EnsureMetadata(GIP_Attachment *attachment) 1248{ 1249 switch (attachment->got_metadata) { 1250 case GIP_METADATA_GOT: 1251 case GIP_METADATA_FAKED: 1252 return true; 1253 case GIP_METADATA_NONE: 1254 if (attachment->device->got_hello) { 1255 attachment->device->timeout = GIP_ACME_TIMEOUT; 1256 attachment->got_metadata = GIP_METADATA_PENDING; 1257 attachment->metadata_next = SDL_GetTicks() + 500; 1258 attachment->metadata_retries = 0; 1259 return GIP_SendSystemMessage(attachment, GIP_CMD_METADATA, 0, NULL, 0); 1260 } else { 1261 return GIP_SetMetadataDefaults(attachment); 1262 } 1263 default: 1264 return true; 1265 } 1266} 1267 1268static bool GIP_SetMetadataDefaults(GIP_Attachment *attachment) 1269{ 1270 if (attachment->attachment_index == 0) { 1271 /* Some decent default settings */ 1272 attachment->features |= GIP_FEATURE_MOTOR_CONTROL; 1273 attachment->attachment_type = GIP_TYPE_GAMEPAD; 1274 attachment->metadata.device.in_system_messages[0] |= (1u << GIP_CMD_GUIDE_BUTTON); 1275 1276 if (SDL_IsJoystickXboxSeriesX(attachment->device->device->vendor_id, attachment->device->device->product_id)) { 1277 attachment->features |= GIP_FEATURE_CONSOLE_FUNCTION_MAP; 1278 } 1279 } 1280 1281 GIP_HandleQuirks(attachment); 1282 1283 if (GIP_SupportsSystemMessage(attachment, GIP_CMD_FIRMWARE, false)) { 1284 GIP_SendQueryFirmware(attachment, 2); 1285 } 1286 1287 attachment->got_metadata = GIP_METADATA_FAKED; 1288 attachment->device->hello_deadline = 0; 1289 if (!attachment->joystick) { 1290 return HIDAPI_JoystickConnected(attachment->device->device, &attachment->joystick); 1291 } 1292 return true; 1293} 1294 1295static bool GIP_HandleCommandProtocolControl( 1296 GIP_Attachment *attachment, 1297 const GIP_Header *header, 1298 const Uint8 *bytes, 1299 int num_bytes) 1300{ 1301 // TODO 1302 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GIP: Unimplemented Protocol Control message"); 1303 return false; 1304} 1305 1306static bool GIP_HandleCommandHelloDevice( 1307 GIP_Attachment *attachment, 1308 const GIP_Header *header, 1309 const Uint8 *bytes, 1310 int num_bytes) 1311{ 1312 GIP_HelloDevice message = {0}; 1313 1314 if (num_bytes != 28) { 1315 return false; 1316 } 1317 1318 message.device_id = (Uint64) bytes[0]; 1319 message.device_id |= (Uint64) bytes[1] << 8; 1320 message.device_id |= (Uint64) bytes[2] << 16; 1321 message.device_id |= (Uint64) bytes[3] << 24; 1322 message.device_id |= (Uint64) bytes[4] << 32; 1323 message.device_id |= (Uint64) bytes[5] << 40; 1324 message.device_id |= (Uint64) bytes[6] << 48; 1325 message.device_id |= (Uint64) bytes[7] << 56; 1326 1327 message.vendor_id = bytes[8]; 1328 message.vendor_id |= bytes[9] << 8; 1329 1330 message.product_id = bytes[10]; 1331 message.product_id |= bytes[11] << 8; 1332 1333 message.firmware_major_version = bytes[12]; 1334 message.firmware_major_version |= bytes[13] << 8; 1335 1336 message.firmware_minor_version = bytes[14]; 1337 message.firmware_minor_version |= bytes[15] << 8; 1338 1339 message.firmware_build_version = bytes[16]; 1340 message.firmware_build_version |= bytes[17] << 8; 1341 1342 message.firmware_revision = bytes[18]; 1343 message.firmware_revision |= bytes[19] << 8; 1344 1345 message.hardware_major_version = bytes[20]; 1346 message.hardware_minor_version = bytes[21]; 1347 1348 message.rf_proto_major_version = bytes[22]; 1349 message.rf_proto_minor_version = bytes[23]; 1350 1351 message.security_major_version = bytes[24]; 1352 message.security_minor_version = bytes[25]; 1353 1354 message.gip_major_version = bytes[26]; 1355 message.gip_minor_version = bytes[27]; 1356 1357 SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, 1358 "GIP: Device hello from %" SDL_PRIx64 " (%04x:%04x)", 1359 message.device_id, message.vendor_id, message.product_id); 1360 SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, 1361 "GIP: Firmware version %d.%d.%d rev %d", 1362 message.firmware_major_version, 1363 message.firmware_minor_version, 1364 message.firmware_build_version, 1365 message.firmware_revision); 1366 1367 /* 1368 * The GIP spec specifies that the host should reject the device if any of these are wrong. 1369 * I don't know if Windows or an Xbox do, however, so let's just log warnings instead. 1370 */ 1371 if (message.rf_proto_major_version != 1 && message.rf_proto_minor_version != 0) { 1372 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, 1373 "GIP: Invalid RF protocol version %d.%d, expected 1.0", 1374 message.rf_proto_major_version, message.rf_proto_minor_version); 1375 } 1376 1377 if (message.security_major_version != 1 && message.security_minor_version != 0) { 1378 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, 1379 "GIP: Invalid security protocol version %d.%d, expected 1.0", 1380 message.security_major_version, message.security_minor_version); 1381 } 1382 1383 if (message.gip_major_version != 1 && message.gip_minor_version != 0) { 1384 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, 1385 "GIP: Invalid GIP version %d.%d, expected 1.0", 1386 message.gip_major_version, message.gip_minor_version); 1387 } 1388 1389 if (header->flags & GIP_FLAG_ATTACHMENT_MASK) { 1390 return GIP_SendSystemMessage(attachment, GIP_CMD_METADATA, 0, NULL, 0); 1391 } else { 1392 attachment->firmware_major_version = message.firmware_major_version; 1393 attachment->firmware_minor_version = message.firmware_minor_version; 1394 1395 if (attachment->attachment_index == 0) { 1396 attachment->device->hello_deadline = 0; 1397 attachment->device->got_hello = true; 1398 } 1399 if (attachment->got_metadata == GIP_METADATA_FAKED) { 1400 attachment->got_metadata = GIP_METADATA_NONE; 1401 } 1402 GIP_EnsureMetadata(attachment); 1403 } 1404 return true; 1405} 1406 1407static bool GIP_HandleCommandStatusDevice( 1408 GIP_Attachment *attachment, 1409 const GIP_Header *header, 1410 const Uint8 *bytes, 1411 int num_bytes) 1412{ 1413 GIP_ExtendedStatus status; 1414 SDL_Joystick *joystick = NULL; 1415 SDL_PowerState power_state; 1416 int power_percent = 0; 1417 int i; 1418 1419 if (num_bytes < 1) { 1420 return false; 1421 } 1422 SDL_zero(status); 1423 status.base.battery_level = bytes[0] & 3; 1424 status.base.battery_type = (bytes[0] >> 2) & 3; 1425 status.base.charge = (bytes[0] >> 4) & 3; 1426 status.base.power_level = (bytes[0] >> 6) & 3; 1427 1428 if (attachment->joystick) { 1429 joystick = SDL_GetJoystickFromID(attachment->joystick); 1430 } 1431 if (joystick) { 1432 switch (status.base.battery_level) { 1433 case GIP_BATTERY_CRITICAL: 1434 power_percent = 1; 1435 break; 1436 case GIP_BATTERY_LOW: 1437 power_percent = 25; 1438 break; 1439 case GIP_BATTERY_MEDIUM: 1440 power_percent = 50; 1441 break; 1442 case GIP_BATTERY_FULL: 1443 power_percent = 100; 1444 break; 1445 } 1446 switch (status.base.charge) { 1447 case GIP_CHARGING: 1448 if (status.base.battery_level == GIP_BATTERY_FULL) { 1449 power_state = SDL_POWERSTATE_CHARGED; 1450 } else { 1451 power_state = SDL_POWERSTATE_CHARGING; 1452 } 1453 break; 1454 case GIP_NOT_CHARGING: 1455 power_state = SDL_POWERSTATE_ON_BATTERY; 1456 break; 1457 case GIP_CHARGE_ERROR: 1458 default: 1459 power_state = SDL_POWERSTATE_UNKNOWN; 1460 break; 1461 } 1462 1463 switch (status.base.battery_type) { 1464 case GIP_BATTERY_ABSENT: 1465 power_state = SDL_POWERSTATE_NO_BATTERY; 1466 break; 1467 case GIP_BATTERY_STANDARD: 1468 case GIP_BATTERY_RECHARGEABLE: 1469 break; 1470 default: 1471 power_state = SDL_POWERSTATE_UNKNOWN; 1472 break; 1473 } 1474 1475 SDL_SendJoystickPowerInfo(joystick, power_state, power_percent); 1476 } 1477 1478 if (num_bytes >= 4) { 1479 status.device_active = bytes[1] & 1; 1480 if (bytes[1] & 2) { 1481 /* Events present */ 1482 if (num_bytes < 5) { 1483 return false; 1484 } 1485 status.num_events = bytes[4]; 1486 if (status.num_events > 5) { 1487 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, 1488 "GIP: Device reported too many events, %d > 5", 1489 status.num_events); 1490 return false; 1491 } 1492 if (5 + status.num_events * 10 > num_bytes) { 1493 return false; 1494 } 1495 for (i = 0; i < status.num_events; i++) { 1496 status.events[i].event_type = bytes[i * 10 + 5]; 1497 status.events[i].event_type |= bytes[i * 10 + 6] << 8; 1498 status.events[i].fault_tag = bytes[i * 10 + 7]; 1499 status.events[i].fault_tag |= bytes[i * 10 + 8] << 8; 1500 status.events[i].fault_tag |= bytes[i * 10 + 9] << 16; 1501 status.events[i].fault_tag |= bytes[i * 10 + 10] << 24; 1502 status.events[i].fault_tag = bytes[i * 10 + 11]; 1503 status.events[i].fault_tag |= bytes[i * 10 + 12] << 8; 1504 status.events[i].fault_tag |= bytes[i * 10 + 13] << 16; 1505 status.events[i].fault_tag |= bytes[i * 10 + 14] << 24; 1506 } 1507 } 1508 } 1509 1510 GIP_EnsureMetadata(attachment); 1511 return true; 1512} 1513 1514static bool GIP_HandleCommandMetadataRespose( 1515 GIP_Attachment *attachment, 1516 const GIP_Header *header, 1517 const Uint8 *bytes, 1518 int num_bytes) 1519{ 1520 GIP_Metadata metadata = {0}; 1521 const GUID *expected_guid = NULL; 1522 bool found_expected_guid; 1523 bool found_controller_guid = false; 1524 int i; 1525 1526 if (!GIP_ParseMetadata(&metadata, bytes, num_bytes)) { 1527 return false; 1528 } 1529 1530 if (attachment->got_metadata == GIP_METADATA_GOT) { 1531 GIP_MetadataFree(&attachment->metadata); 1532 } 1533 attachment->metadata = metadata; 1534 attachment->got_metadata = GIP_METADATA_GOT; 1535 attachment->features = 0; 1536 1537 attachment->attachment_type = GIP_TYPE_UNKNOWN; 1538#ifdef DEBUG_XBOX_PROTOCOL 1539 for (i = 0; i < metadata.device.num_preferred_types; i++) { 1540 const char *type = metadata.device.preferred_types[i]; 1541 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GIP: Device preferred type: %s", type); 1542 } 1543#endif 1544 for (i = 0; i < metadata.device.num_preferred_types; i++) { 1545 const char *type = metadata.device.preferred_types[i]; 1546 if (SDL_strcmp(type, "Windows.Xbox.Input.Gamepad") == 0) { 1547 attachment->attachment_type = GIP_TYPE_GAMEPAD; 1548 expected_guid = &GUID_IGamepad; 1549 break; 1550 } 1551 if (SDL_strcmp(type, "Microsoft.Xbox.Input.ArcadeStick") == 0) { 1552 attachment->attachment_type = GIP_TYPE_ARCADE_STICK; 1553 expected_guid = &GUID_ArcadeStick; 1554 break; 1555 } 1556 if (SDL_strcmp(type, "Windows.Xbox.Input.ArcadeStick") == 0) { 1557 attachment->attachment_type = GIP_TYPE_ARCADE_STICK; 1558 expected_guid = &GUID_ArcadeStick; 1559 break; 1560 } 1561 if (SDL_strcmp(type, "Microsoft.Xbox.Input.FlightStick") == 0) { 1562 attachment->attachment_type = GIP_TYPE_FLIGHT_STICK; 1563 expected_guid = &GUID_FlightStick; 1564 break; 1565 } 1566 if (SDL_strcmp(type, "Windows.Xbox.Input.FlightStick") == 0) { 1567 attachment->attachment_type = GIP_TYPE_FLIGHT_STICK; 1568 expected_guid = &GUID_FlightStick; 1569 break; 1570 } 1571 if (SDL_strcmp(type, "Microsoft.Xbox.Input.Wheel") == 0) { 1572 attachment->attachment_type = GIP_TYPE_WHEEL; 1573 expected_guid = &GUID_Wheel; 1574 break; 1575 } 1576 if (SDL_strcmp(type, "Windows.Xbox.Input.Wheel") == 0) { 1577 attachment->attachment_type = GIP_TYPE_WHEEL; 1578 expected_guid = &GUID_Wheel; 1579 break; 1580 } 1581 if (SDL_strcmp(type, "Windows.Xbox.Input.NavigationController") == 0) { 1582 attachment->attachment_type = GIP_TYPE_NAVIGATION_CONTROLLER; 1583 expected_guid = &GUID_NavigationController; 1584 break; 1585 } 1586 if (SDL_strcmp(type, "Windows.Xbox.Input.Chatpad") == 0) { 1587 attachment->attachment_type = GIP_TYPE_CHATPAD; 1588 break; 1589 } 1590 if (SDL_strcmp(type, "Windows.Xbox.Input.Headset") == 0) { 1591 attachment->attachment_type = GIP_TYPE_HEADSET; 1592 expected_guid = &GUID_IHeadset; 1593 break; 1594 } 1595 } 1596 1597 found_expected_guid = !expected_guid; 1598 for (i = 0; i < metadata.device.num_supported_interfaces; i++) { 1599 const GUID* guid = &metadata.device.supported_interfaces[i]; 1600#ifdef DEBUG_XBOX_PROTOCOL 1601 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 1602 "GIP: Supported interface: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 1603 guid->a, guid->b, guid->c, guid->d[0], guid->d[1], 1604 guid->d[2], guid->d[3], guid->d[4], guid->d[5], guid->d[6], guid->d[7]); 1605#endif 1606 if (expected_guid && SDL_memcmp(expected_guid, guid, sizeof(GUID)) == 0) { 1607 found_expected_guid = true; 1608 } 1609 if (SDL_memcmp(&GUID_IController, guid, sizeof(GUID)) == 0) { 1610 found_controller_guid = true; 1611 continue; 1612 } 1613 if (SDL_memcmp(&GUID_IDevAuthPCOptOut, guid, sizeof(GUID)) == 0) { 1614 attachment->features |= GIP_FEATURE_SECURITY_OPT_OUT; 1615 continue; 1616 } 1617 if (SDL_memcmp(&GUID_IConsoleFunctionMap_InputReport, guid, sizeof(GUID)) == 0) { 1618 attachment->features |= GIP_FEATURE_CONSOLE_FUNCTION_MAP; 1619 continue; 1620 } 1621 if (SDL_memcmp(&GUID_IConsoleFunctionMap_OverflowInputReport, guid, sizeof(GUID)) == 0) { 1622 attachment->features |= GIP_FEATURE_CONSOLE_FUNCTION_MAP_OVERFLOW; 1623 continue; 1624 } 1625 if (SDL_memcmp(&GUID_IEliteButtons, guid, sizeof(GUID)) == 0) { 1626 attachment->features |= GIP_FEATURE_ELITE_BUTTONS; 1627 continue; 1628 } 1629 if (SDL_memcmp(&GUID_DynamicLatencyInput, guid, sizeof(GUID)) == 0) { 1630 attachment->features |= GIP_FEATURE_DYNAMIC_LATENCY_INPUT; 1631 continue; 1632 } 1633 } 1634 1635 for (i = 0; i < metadata.num_messages; i++) { 1636 GIP_MessageMetadata *message = &metadata.message_metadata[i]; 1637 if (message->type == GIP_CMD_DIRECT_MOTOR && message->length >= 9 && 1638 (message->flags & GIP_MESSAGE_FLAG_DOWNSTREAM)) { 1639 attachment->features |= GIP_FEATURE_MOTOR_CONTROL; 1640 } 1641 } 1642 1643 if (!found_expected_guid || (GIP_AttachmentIsController(attachment) && !found_controller_guid)) { 1644 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 1645 "GIP: Controller was missing expected GUID. This controller probably won't work on an actual Xbox."); 1646 } 1647 1648 if ((attachment->features & GIP_FEATURE_GUIDE_COLOR) && 1649 !GIP_SupportsVendorMessage(attachment, GIP_CMD_GUIDE_COLOR, false)) 1650 { 1651 attachment->features &= ~GIP_FEATURE_GUIDE_COLOR; 1652 } 1653 1654 GIP_HandleQuirks(attachment); 1655 1656 return GIP_SendInitSequence(attachment); 1657} 1658 1659static bool GIP_HandleCommandSecurity( 1660 GIP_Attachment *attachment, 1661 const GIP_Header *header, 1662 const Uint8 *bytes, 1663 int num_bytes) 1664{ 1665 // TODO 1666 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GIP: Unimplemented Security message"); 1667 return false; 1668} 1669 1670static bool GIP_HandleCommandGuideButtonStatus( 1671 GIP_Attachment *attachment, 1672 const GIP_Header *header, 1673 const Uint8 *bytes, 1674 int num_bytes) 1675{ 1676 Uint64 timestamp = SDL_GetTicksNS(); 1677 SDL_Joystick *joystick = NULL; 1678 1679 if (attachment->device->device->num_joysticks < 1) { 1680 return true; 1681 } 1682 1683 joystick = SDL_GetJoystickFromID(attachment->joystick); 1684 if (!joystick) { 1685 return false; 1686 } 1687 if (bytes[1] == VK_LWIN) { 1688 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, (bytes[0] & 0x03) != 0); 1689 } 1690 1691 return true; 1692} 1693 1694static bool GIP_HandleCommandAudioControl( 1695 GIP_Attachment *attachment, 1696 const GIP_Header *header, 1697 const Uint8 *bytes, 1698 int num_bytes) 1699{ 1700 // TODO 1701 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GIP: Unimplemented Audio Control message"); 1702 return false; 1703} 1704 1705static bool GIP_HandleCommandFirmware( 1706 GIP_Attachment *attachment, 1707 const GIP_Header *header, 1708 const Uint8 *bytes, 1709 int num_bytes) 1710{ 1711 if (num_bytes < 1) { 1712 return false; 1713 } 1714 if (bytes[0] == 1) { 1715 Uint16 major, minor, build, rev; 1716 1717 if (num_bytes < 14) { 1718 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GIP: Discarding too-short firmware message"); 1719 1720 return false; 1721 } 1722 major = bytes[6]; 1723 major |= bytes[7] << 8; 1724 minor = bytes[8]; 1725 minor |= bytes[9] << 8; 1726 build = bytes[10]; 1727 build |= bytes[11] << 8; 1728 rev = bytes[12]; 1729 rev |= bytes[13] << 8; 1730 1731 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GIP: Firmware version: %d.%d.%d rev %d", major, minor, build, rev); 1732 1733 attachment->firmware_major_version = major; 1734 attachment->firmware_minor_version = minor; 1735 1736 if (attachment->device->device->vendor_id == USB_VENDOR_MICROSOFT && 1737 attachment->device->device->product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2) 1738 { 1739 return GIP_EnableEliteButtons(attachment); 1740 } 1741 return true; 1742 } else { 1743 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GIP: Unimplemented Firmware message"); 1744 1745 return false; 1746 } 1747} 1748 1749static bool GIP_HandleCommandRawReport( 1750 GIP_Attachment *attachment, 1751 const GIP_Header *header, 1752 const Uint8 *bytes, 1753 int num_bytes) 1754{ 1755 Uint64 timestamp = SDL_GetTicksNS(); 1756 SDL_Joystick *joystick = NULL; 1757 1758 if (attachment->device->device->num_joysticks < 1) { 1759 return true; 1760 } 1761 1762 joystick = SDL_GetJoystickFromID(attachment->joystick); 1763 if (!joystick) { 1764 return true; 1765 } 1766 1767 if (num_bytes < 17) { 1768 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GIP: Discarding too-short raw report"); 1769 return false; 1770 } 1771 1772 if ((attachment->features & GIP_FEATURE_ELITE_BUTTONS) && attachment->xbe_format == GIP_BTN_FMT_XBE2_RAW) { 1773 if (bytes[15] & 3) { 1774 SDL_SendJoystickButton(timestamp, 1775 joystick, 1776 attachment->paddle_idx, 1777 0); 1778 SDL_SendJoystickButton(timestamp, 1779 joystick, 1780 attachment->paddle_idx + 1, 1781 0); 1782 SDL_SendJoystickButton(timestamp, 1783 joystick, 1784 attachment->paddle_idx + 2, 1785 0); 1786 SDL_SendJoystickButton(timestamp, 1787 joystick, 1788 attachment->paddle_idx + 3, 1789 0); 1790 } else { 1791 SDL_SendJoystickButton(timestamp, 1792 joystick, 1793 attachment->paddle_idx, 1794 (bytes[GIP_BTN_OFFSET_XBE2] & 0x01) != 0); 1795 SDL_SendJoystickButton(timestamp, 1796 joystick, 1797 attachment->paddle_idx + 1, 1798 (bytes[GIP_BTN_OFFSET_XBE2] & 0x02) != 0); 1799 SDL_SendJoystickButton(timestamp, 1800 joystick, 1801 attachment->paddle_idx + 2, 1802 (bytes[GIP_BTN_OFFSET_XBE2] & 0x04) != 0); 1803 SDL_SendJoystickButton(timestamp, 1804 joystick, 1805 attachment->paddle_idx + 3, 1806 (bytes[GIP_BTN_OFFSET_XBE2] & 0x08) != 0); 1807 } 1808 } 1809 return true; 1810} 1811 1812static bool GIP_HandleCommandHidReport( 1813 GIP_Attachment *attachment, 1814 const GIP_Header *header, 1815 const Uint8 *bytes, 1816 int num_bytes) 1817{ 1818 Uint64 timestamp = SDL_GetTicksNS(); 1819 // SDL doesn't have HID descriptor parsing, so we have to hardcode for the Chatpad descriptor instead. 1820 // I don't know of any other devices that emit HID reports, so this should be safe. 1821 if (attachment->attachment_type != GIP_TYPE_CHATPAD || !attachment->keyboard || num_bytes != 8) { 1822 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GIP: Unimplemented HID Report message"); 1823 return false; 1824 } 1825 1826 Uint8 modifiers = bytes[0]; 1827 Uint8 changed_modifiers = modifiers ^ attachment->last_modifiers; 1828 if (changed_modifiers & 0x02) { 1829 if (modifiers & 0x02) { 1830 SDL_SendKeyboardKey(timestamp, attachment->keyboard, 0, SDL_SCANCODE_LSHIFT, true); 1831 } else { 1832 SDL_SendKeyboardKey(timestamp, attachment->keyboard, 0, SDL_SCANCODE_LSHIFT, false); 1833 } 1834 } 1835 // The chatpad has several non-ASCII characters that it sends as Alt codes 1836 if (changed_modifiers & 0x04) { 1837 if (modifiers & 0x04) { 1838 attachment->altcode_digit = 0; 1839 attachment->altcode = 0; 1840 } else { 1841 if (attachment->altcode_digit == 4) { 1842 char utf8[4] = {0}; 1843 // Some Alt codes don't match their Unicode codepoint for some reason 1844 switch (attachment->altcode) { 1845 case 128: 1846 SDL_UCS4ToUTF8(0x20AC, utf8); 1847 break; 1848 case 138: 1849 SDL_UCS4ToUTF8(0x0160, utf8); 1850 break; 1851 case 140: 1852 SDL_UCS4ToUTF8(0x0152, utf8); 1853 break; 1854 case 154: 1855 SDL_UCS4ToUTF8(0x0161, utf8); 1856 break; 1857 case 156: 1858 SDL_UCS4ToUTF8(0x0153, utf8); 1859 break; 1860 default: 1861 SDL_UCS4ToUTF8(attachment->altcode, utf8); 1862 break; 1863 } 1864 SDL_SendKeyboardText(utf8); 1865 } 1866 attachment->altcode_digit = -1; 1867 SDL_SendKeyboardKey(timestamp, attachment->keyboard, 0, SDL_SCANCODE_NUMLOCKCLEAR, true); 1868 SDL_SendKeyboardKey(timestamp, attachment->keyboard, 0, SDL_SCANCODE_NUMLOCKCLEAR, false); 1869 } 1870 } 1871 1872 if (!bytes[2] && attachment->last_key) { 1873 if (attachment->last_key == SDL_SCANCODE_CAPSLOCK) { 1874 attachment->capslock = !attachment->capslock; 1875 } 1876 SDL_SendKeyboardKey(timestamp, attachment->keyboard, 0, attachment->last_key, false); 1877 if (!(attachment->last_modifiers & 0xfd)) { 1878 SDL_Keycode keycode = SDL_GetKeymapKeycode(NULL, 1879 attachment->last_key, 1880 ((attachment->last_modifiers & 0x02) || attachment->capslock) ? SDL_KMOD_SHIFT : 0); 1881 if (keycode && keycode < 0x80) { 1882 char text[2] = { (char)keycode }; 1883 SDL_SendKeyboardText(text); 1884 } 1885 } 1886 attachment->last_key = 0; 1887 } else { 1888 SDL_SendKeyboardKey(timestamp, attachment->keyboard, 0, bytes[2], true); 1889 attachment->last_key = bytes[2]; 1890 1891 if ((modifiers & 0x04) && attachment->altcode_digit >= 0) { 1892 int digit = bytes[2] - SDL_SCANCODE_KP_1 + 1; 1893 if (digit < 1 || digit > 10) { 1894 attachment->altcode_digit = -1; 1895 } else { 1896 attachment->altcode_digit++; 1897 attachment->altcode *= 10; 1898 if (digit < 10) { 1899 attachment->altcode += digit; 1900 } 1901 } 1902 } 1903 } 1904 1905 attachment->last_modifiers = modifiers; 1906 return true; 1907} 1908 1909static bool GIP_HandleCommandExtended( 1910 GIP_Attachment *attachment, 1911 const GIP_Header *header, 1912 const Uint8 *bytes, 1913 int num_bytes) 1914{ 1915 char serial[33] = {0}; 1916 1917 if (num_bytes < 2) { 1918 return false; 1919 } 1920 1921 switch (bytes[0]) { 1922 case GIP_EXTCMD_GET_SERIAL_NUMBER: 1923 if (bytes[1] != GIP_EXTENDED_STATUS_OK) { 1924 return true; 1925 } 1926 if (header->flags & GIP_FLAG_ATTACHMENT_MASK) { 1927 return true; 1928 } 1929 SDL_memcpy(serial, &bytes[2], SDL_min(sizeof(serial) - 1, num_bytes - 2)); 1930 HIDAPI_SetDeviceSerial(attachment->device->device, serial); 1931 break; 1932 default: 1933 // TODO 1934 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GIP: Extended message type %02x", bytes[0]); 1935 return false; 1936 } 1937 1938 return true; 1939} 1940 1941static void GIP_HandleNavigationReport( 1942 GIP_Attachment *attachment, 1943 SDL_Joystick *joystick, 1944 Uint64 timestamp, 1945 const Uint8 *bytes, 1946 int num_bytes) 1947{ 1948 if (attachment->last_input[0] != bytes[0]) { 1949 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((bytes[0] & 0x04) != 0)); 1950 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((bytes[0] & 0x08) != 0)); 1951 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((bytes[0] & 0x10) != 0)); 1952 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((bytes[0] & 0x20) != 0)); 1953 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((bytes[0] & 0x40) != 0)); 1954 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((bytes[0] & 0x80) != 0)); 1955 } 1956 1957 if (attachment->last_input[1] != bytes[1]) { 1958 Uint8 hat = 0; 1959 1960 if (bytes[1] & 0x01) { 1961 hat |= SDL_HAT_UP; 1962 } 1963 if (bytes[1] & 0x02) { 1964 hat |= SDL_HAT_DOWN; 1965 } 1966 if (bytes[1] & 0x04) { 1967 hat |= SDL_HAT_LEFT; 1968 } 1969 if (bytes[1] & 0x08) { 1970 hat |= SDL_HAT_RIGHT; 1971 } 1972 SDL_SendJoystickHat(timestamp, joystick, 0, hat); 1973 1974 if (attachment->attachment_type == GIP_TYPE_ARCADE_STICK) { 1975 /* Previous */ 1976 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((bytes[1] & 0x10) != 0)); 1977 /* Next */ 1978 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((bytes[1] & 0x20) != 0)); 1979 } else { 1980 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((bytes[1] & 0x10) != 0)); 1981 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((bytes[1] & 0x20) != 0)); 1982 } 1983 } 1984} 1985 1986static void GIP_HandleGamepadReport( 1987 GIP_Attachment *attachment, 1988 SDL_Joystick *joystick, 1989 Uint64 timestamp, 1990 const Uint8 *bytes, 1991 int num_bytes) 1992{ 1993 Sint16 axis; 1994 1995 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((bytes[1] & 0x40) != 0)); 1996 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((bytes[1] & 0x80) != 0)); 1997 1998 axis = bytes[2]; 1999 axis |= bytes[3] << 8; 2000 axis = SDL_clamp(axis, 0, 1023); 2001 axis = (axis - 512) * 64; 2002 if (axis == 32704) { 2003 axis = 32767; 2004 } 2005 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis); 2006 2007 axis = bytes[4]; 2008 axis |= bytes[5] << 8; 2009 axis = SDL_clamp(axis, 0, 1023); 2010 axis = (axis - 512) * 64; 2011 if (axis == 32704) { 2012 axis = 32767; 2013 } 2014 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis); 2015 2016 axis = bytes[6]; 2017 axis |= bytes[7] << 8; 2018 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis); 2019 axis = bytes[8]; 2020 axis |= bytes[9] << 8; 2021 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, ~axis); 2022 axis = bytes[10]; 2023 axis |= bytes[11] << 8; 2024 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis); 2025 axis = bytes[12]; 2026 axis |= bytes[13] << 8; 2027 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, ~axis); 2028} 2029 2030static void GIP_HandleArcadeStickReport( 2031 GIP_Attachment *attachment, 2032 SDL_Joystick *joystick, 2033 Uint64 timestamp, 2034 const Uint8 *bytes, 2035 int num_bytes) 2036{ 2037 Sint16 axis; 2038 axis = bytes[2]; 2039 axis |= bytes[3] << 8; 2040 axis = SDL_clamp(axis, 0, 1023); 2041 axis = (axis - 512) * 64; 2042 if (axis == 32704) { 2043 axis = 32767; 2044 } 2045 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis); 2046 2047 axis = bytes[4]; 2048 axis |= bytes[5] << 8; 2049 axis = SDL_clamp(axis, 0, 1023); 2050 axis = (axis - 512) * 64; 2051 if (axis == 32704) { 2052 axis = 32767; 2053 } 2054 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis); 2055 2056 if (num_bytes >= 19) { 2057 /* Extra button 6 */ 2058 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, (bytes[18] & 0x40) ? 32767 : -32768); 2059 /* Extra button 7 */ 2060 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, (bytes[18] & 0x80) ? 32767 : -32768); 2061 } 2062} 2063 2064static void GIP_HandleFlightStickReport( 2065 GIP_Attachment *attachment, 2066 SDL_Joystick *joystick, 2067 Uint64 timestamp, 2068 const Uint8 *bytes, 2069 int num_bytes) 2070{ 2071 Sint16 axis; 2072 int i; 2073 2074 if (num_bytes < 19) { 2075 return; 2076 } 2077 2078 if (attachment->last_input[2] != bytes[2]) { 2079 /* Fire 1 and 2 */ 2080 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((bytes[2] & 0x01) != 0)); 2081 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((bytes[2] & 0x02) != 0)); 2082 } 2083 for (i = 0; i < attachment->extra_buttons;) { 2084 if (attachment->last_input[i / 8 + 3] != bytes[i / 8 + 3]) { 2085 for (; i < attachment->extra_buttons; i++) { 2086 SDL_SendJoystickButton(timestamp, 2087 joystick, 2088 (Uint8) (attachment->extra_button_idx + i), 2089 ((bytes[i / 8 + 3] & (1u << i)) != 0)); 2090 } 2091 } else { 2092 i += 8; 2093 } 2094 } 2095 2096 /* Roll, pitch and yaw are signed. Throttle and any extra axes are unsigned. All values are full-range. */ 2097 axis = bytes[11]; 2098 axis |= bytes[12] << 8; 2099 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis); 2100 2101 axis = bytes[13]; 2102 axis |= bytes[14] << 8; 2103 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis); 2104 2105 axis = bytes[15]; 2106 axis |= bytes[16] << 8; 2107 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis); 2108 2109 /* There are no more signed values, so skip RIGHTY */ 2110 2111 axis = (bytes[18] << 8) - 0x8000; 2112 axis |= bytes[17]; 2113 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis); 2114 2115 for (i = 0; i < attachment->extra_axes; i++) { 2116 if (20 + i * 2 >= num_bytes) { 2117 return; 2118 } 2119 axis = (bytes[20 + i * 2] << 8) - 0x8000; 2120 axis |= bytes[19 + i * 2]; 2121 SDL_SendJoystickAxis(timestamp, joystick, (Uint8) (SDL_GAMEPAD_AXIS_RIGHT_TRIGGER + i), axis); 2122 } 2123} 2124 2125static bool GIP_HandleLLInputReport( 2126 GIP_Attachment *attachment, 2127 const GIP_Header *header, 2128 const Uint8 *bytes, 2129 int num_bytes) 2130{ 2131 Uint64 timestamp = SDL_GetTicksNS(); 2132 SDL_Joystick *joystick = NULL; 2133 2134 if (attachment->device->device->num_joysticks < 1) { 2135 GIP_EnsureMetadata(attachment); 2136 if (attachment->got_metadata != GIP_METADATA_GOT && attachment->got_metadata != GIP_METADATA_FAKED) { 2137 return true; 2138 } 2139 } 2140 2141 joystick = SDL_GetJoystickFromID(attachment->joystick); 2142 if (!joystick) { 2143 return false; 2144 } 2145 2146 if (attachment->device_state != GIP_STATE_START) { 2147 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GIP: Discarding early input report"); 2148 attachment->device_state = GIP_STATE_START; 2149 return true; 2150 } 2151 2152 if (num_bytes < 14) { 2153 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GIP: Discarding too-short input report"); 2154 return false; 2155 } 2156 2157 GIP_HandleNavigationReport(attachment, joystick, timestamp, bytes, num_bytes); 2158 2159 switch (attachment->attachment_type) { 2160 case GIP_TYPE_GAMEPAD: 2161 default: 2162 GIP_HandleGamepadReport(attachment, joystick, timestamp, bytes, num_bytes); 2163 break; 2164 case GIP_TYPE_ARCADE_STICK: 2165 GIP_HandleArcadeStickReport(attachment, joystick, timestamp, bytes, num_bytes); 2166 break; 2167 case GIP_TYPE_FLIGHT_STICK: 2168 GIP_HandleFlightStickReport(attachment, joystick, timestamp, bytes, num_bytes); 2169 break; 2170 } 2171 2172 if (attachment->features & GIP_FEATURE_ELITE_BUTTONS) { 2173 bool clear = false; 2174 if (attachment->xbe_format == GIP_BTN_FMT_XBE1 && 2175 num_bytes > GIP_BTN_OFFSET_XBE1 && 2176 attachment->last_input[GIP_BTN_OFFSET_XBE1] != bytes[GIP_BTN_OFFSET_XBE1] && 2177 (bytes[GIP_BTN_OFFSET_XBE1] & 0x10)) 2178 { 2179 SDL_SendJoystickButton(timestamp, 2180 joystick, 2181 attachment->paddle_idx, 2182 (bytes[GIP_BTN_OFFSET_XBE1] & 0x02) != 0); 2183 SDL_SendJoystickButton(timestamp, 2184 joystick, 2185 attachment->paddle_idx + 1, 2186 (bytes[GIP_BTN_OFFSET_XBE1] & 0x08) != 0); 2187 SDL_SendJoystickButton(timestamp, 2188 joystick, 2189 attachment->paddle_idx + 2, 2190 (bytes[GIP_BTN_OFFSET_XBE1] & 0x01) != 0); 2191 SDL_SendJoystickButton(timestamp, 2192 joystick, 2193 attachment->paddle_idx + 3, 2194 (bytes[GIP_BTN_OFFSET_XBE1] & 0x04) != 0); 2195 } else if ((attachment->xbe_format == GIP_BTN_FMT_XBE2_4 || 2196 attachment->xbe_format == GIP_BTN_FMT_XBE2_5) && 2197 num_bytes > GIP_BTN_OFFSET_XBE2) 2198 { 2199 int profile_offset = attachment->xbe_format == GIP_BTN_FMT_XBE2_4 ? 15 : 20; 2200 if (attachment->last_input[GIP_BTN_OFFSET_XBE2] != bytes[GIP_BTN_OFFSET_XBE2] || 2201 attachment->last_input[profile_offset] != bytes[profile_offset]) 2202 { 2203 if (bytes[profile_offset] & 3) { 2204 clear = true; 2205 } else { 2206 SDL_SendJoystickButton(timestamp, 2207 joystick, 2208 attachment->paddle_idx, 2209 (bytes[GIP_BTN_OFFSET_XBE2] & 0x01) != 0); 2210 SDL_SendJoystickButton(timestamp, 2211 joystick, 2212 attachment->paddle_idx + 1, 2213 (bytes[GIP_BTN_OFFSET_XBE2] & 0x02) != 0); 2214 SDL_SendJoystickButton(timestamp, 2215 joystick, 2216 attachment->paddle_idx + 2, 2217 (bytes[GIP_BTN_OFFSET_XBE2] & 0x04) != 0); 2218 SDL_SendJoystickButton(timestamp, 2219 joystick, 2220 attachment->paddle_idx + 3, 2221 (bytes[GIP_BTN_OFFSET_XBE2] & 0x08) != 0); 2222 } 2223 } 2224 } else { 2225 clear = true; 2226 } 2227 if (clear) { 2228 SDL_SendJoystickButton(timestamp, 2229 joystick, 2230 attachment->paddle_idx, 2231 0); 2232 SDL_SendJoystickButton(timestamp, 2233 joystick, 2234 attachment->paddle_idx + 1, 2235 0); 2236 SDL_SendJoystickButton(timestamp, 2237 joystick, 2238 attachment->paddle_idx + 2, 2239 0); 2240 SDL_SendJoystickButton(timestamp, 2241 joystick, 2242 attachment->paddle_idx + 3, 2243 0); 2244 } 2245 } 2246 2247 if ((attachment->features & GIP_FEATURE_CONSOLE_FUNCTION_MAP) && num_bytes >= 32) { 2248 int function_map_offset = -1; 2249 if (attachment->features & GIP_FEATURE_DYNAMIC_LATENCY_INPUT) { 2250 /* The dynamic latency input bytes are after the console function map */ 2251 if (num_bytes >= 40) { 2252 function_map_offset = num_bytes - 26; 2253 } 2254 } else { 2255 function_map_offset = num_bytes - 18; 2256 } 2257 if (function_map_offset >= 14) { 2258 if (attachment->last_input[function_map_offset] != bytes[function_map_offset]) { 2259 SDL_SendJoystickButton(timestamp, 2260 joystick, 2261 attachment->share_button_idx, 2262 (bytes[function_map_offset] & 0x01) != 0); 2263 } 2264 } 2265 } 2266 2267 SDL_memcpy(attachment->last_input, bytes, SDL_min(num_bytes, sizeof(attachment->last_input))); 2268 2269 return true; 2270} 2271 2272static bool GIP_HandleLLStaticConfiguration( 2273 GIP_Attachment *attachment, 2274 const GIP_Header *header, 2275 const Uint8 *bytes, 2276 int num_bytes) 2277{ 2278 // TODO 2279 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GIP: Unimplemented Static Configuration message"); 2280 return false; 2281} 2282 2283static bool GIP_HandleLLButtonInfoReport( 2284 GIP_Attachment *attachment, 2285 const GIP_Header *header, 2286 const Uint8 *bytes, 2287 int num_bytes) 2288{ 2289 // TODO 2290 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GIP: Unimplemented Button Info Report message"); 2291 return false; 2292} 2293 2294static bool GIP_HandleLLOverflowInputReport( 2295 GIP_Attachment *attachment, 2296 const GIP_Header *header, 2297 const Uint8 *bytes, 2298 int num_bytes) 2299{ 2300 // TODO 2301 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GIP: Unimplemented Overflow Input Report message"); 2302 return false; 2303} 2304 2305static bool GIP_HandleAudioData( 2306 GIP_Attachment *attachment, 2307 const GIP_Header *header, 2308 const Uint8 *bytes, 2309 int num_bytes) 2310{ 2311 // TODO 2312 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "GIP: Unimplemented Audio Data message"); 2313 return false; 2314} 2315 2316static bool GIP_HandleSystemMessage( 2317 GIP_Attachment *attachment, 2318 const GIP_Header *header, 2319 const Uint8 *bytes, 2320 int num_bytes) 2321{ 2322 if (attachment->attachment_index > 0 && attachment->attachment_type == GIP_TYPE_UNKNOWN) { 2323 // XXX If we reattach to a controller after it's been initialized, it might have 2324 // attachments we don't know about. Try to figure out what this one is. 2325 if (header->message_type == GIP_CMD_HID_REPORT && num_bytes == 8) { 2326 if (!attachment->keyboard) { 2327 attachment->keyboard = (SDL_KeyboardID)(uintptr_t) attachment; 2328 SDL_AddKeyboard(attachment->keyboard, "Xbox One Chatpad"); 2329 } 2330 attachment->attachment_type = GIP_TYPE_CHATPAD; 2331 attachment->metadata.device.in_system_messages[0] |= (1u << GIP_CMD_HID_REPORT); 2332 } 2333 } 2334 if (!GIP_SupportsSystemMessage(attachment, header->message_type, true)) { 2335 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, 2336 "GIP: Received claimed-unsupported system message type %02x", 2337 header->message_type); 2338 return false; 2339 } 2340 switch (header->message_type) { 2341 case GIP_CMD_PROTO_CONTROL: 2342 return GIP_HandleCommandProtocolControl(attachment, header, bytes, num_bytes); 2343 case GIP_CMD_HELLO_DEVICE: 2344 return GIP_HandleCommandHelloDevice(attachment, header, bytes, num_bytes); 2345 case GIP_CMD_STATUS_DEVICE: 2346 return GIP_HandleCommandStatusDevice(attachment, header, bytes, num_bytes); 2347 case GIP_CMD_METADATA: 2348 return GIP_HandleCommandMetadataRespose(attachment, header, bytes, num_bytes); 2349 case GIP_CMD_SECURITY: 2350 return GIP_HandleCommandSecurity(attachment, header, bytes, num_bytes); 2351 case GIP_CMD_GUIDE_BUTTON: 2352 return GIP_HandleCommandGuideButtonStatus(attachment, header, bytes, num_bytes); 2353 case GIP_CMD_AUDIO_CONTROL: 2354 return GIP_HandleCommandAudioControl(attachment, header, bytes, num_bytes); 2355 case GIP_CMD_FIRMWARE: 2356 return GIP_HandleCommandFirmware(attachment, header, bytes, num_bytes); 2357 case GIP_CMD_HID_REPORT: 2358 return GIP_HandleCommandHidReport(attachment, header, bytes, num_bytes); 2359 case GIP_CMD_EXTENDED: 2360 return GIP_HandleCommandExtended(attachment, header, bytes, num_bytes); 2361 case GIP_AUDIO_DATA: 2362 return GIP_HandleAudioData(attachment, header, bytes, num_bytes); 2363 default: 2364 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, 2365 "GIP: Received unknown system message type %02x", 2366 header->message_type); 2367 return false; 2368 } 2369} 2370 2371static GIP_Attachment *GIP_EnsureAttachment(GIP_Device *device, Uint8 attachment_index) 2372{ 2373 GIP_Attachment *attachment = device->attachments[attachment_index]; 2374 if (!attachment) { 2375 attachment = SDL_calloc(1, sizeof(*attachment)); 2376 attachment->attachment_index = attachment_index; 2377 if (attachment_index > 0) { 2378 attachment->attachment_type = GIP_TYPE_UNKNOWN; 2379 } 2380 attachment->device = device; 2381 attachment->metadata.device.in_system_messages[0] = GIP_DEFAULT_IN_SYSTEM_MESSAGES; 2382 attachment->metadata.device.out_system_messages[0] = GIP_DEFAULT_OUT_SYSTEM_MESSAGES; 2383 device->attachments[attachment_index] = attachment; 2384 } 2385 return attachment; 2386} 2387 2388static bool GIP_HandleMessage( 2389 GIP_Attachment *attachment, 2390 const GIP_Header *header, 2391 const Uint8 *bytes, 2392 int num_bytes) 2393{ 2394 if (header->flags & GIP_FLAG_SYSTEM) { 2395 return GIP_HandleSystemMessage(attachment, header, bytes, num_bytes); 2396 } else { 2397 switch (header->message_type) { 2398 case GIP_CMD_RAW_REPORT: 2399 if (attachment->features & GIP_FEATURE_ELITE_BUTTONS) { 2400 return GIP_HandleCommandRawReport(attachment, header, bytes, num_bytes); 2401 } 2402 break; 2403 case GIP_LL_INPUT_REPORT: 2404 return GIP_HandleLLInputReport(attachment, header, bytes, num_bytes); 2405 case GIP_LL_STATIC_CONFIGURATION: 2406 return GIP_HandleLLStaticConfiguration(attachment, header, bytes, num_bytes); 2407 case GIP_LL_BUTTON_INFO_REPORT: 2408 return GIP_HandleLLButtonInfoReport(attachment, header, bytes, num_bytes); 2409 case GIP_LL_OVERFLOW_INPUT_REPORT: 2410 return GIP_HandleLLOverflowInputReport(attachment, header, bytes, num_bytes); 2411 } 2412 } 2413 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, 2414 "GIP: Received unknown vendor message type %02x", 2415 header->message_type); 2416 return false; 2417} 2418 2419static void GIP_ReceivePacket(GIP_Device *device, const Uint8 *bytes, int num_bytes) 2420{ 2421 GIP_Header header; 2422 int offset = 3; 2423 bool ok = true; 2424 Uint64 fragment_offset = 0; 2425 Uint16 bytes_remaining = 0; 2426 bool is_fragment; 2427 Uint8 attachment_index; 2428 GIP_Attachment *attachment; 2429 2430 if (num_bytes < 5) { 2431 return; 2432 } 2433 2434 header.message_type = bytes[0]; 2435 header.flags = bytes[1]; 2436 header.sequence_id = bytes[2]; 2437 offset += GIP_DecodeLength(&header.length, &bytes[offset], num_bytes - offset); 2438 2439 is_fragment = header.flags & GIP_FLAG_FRAGMENT; 2440 attachment_index = header.flags & GIP_FLAG_ATTACHMENT_MASK; 2441 attachment = GIP_EnsureAttachment(device, attachment_index); 2442 2443#ifdef DEBUG_XBOX_PROTOCOL 2444 HIDAPI_DumpPacket("GIP received message: size = %d", bytes, num_bytes); 2445#endif 2446 2447 /* Handle coalescing fragmented messages */ 2448 if (is_fragment) { 2449 if (header.flags & GIP_FLAG_INIT_FRAG) { 2450 Uint64 total_length; 2451 if (attachment->fragment_message) { 2452 /* 2453 * Reset fragment buffer if we get a new initial 2454 * fragment before finishing the last message. 2455 * TODO: Is this the correct behavior? 2456 */ 2457 if (attachment->fragment_data) { 2458 SDL_free(attachment->fragment_data); 2459 attachment->fragment_data = NULL; 2460 } 2461 } 2462 offset += GIP_DecodeLength(&total_length, &bytes[offset], num_bytes - offset); 2463 if (total_length > MAX_MESSAGE_LENGTH) { 2464 return; 2465 } 2466 attachment->total_length = (Uint16) total_length; 2467 attachment->fragment_message = header.message_type; 2468 if (header.length > num_bytes - offset) { 2469 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, 2470 "GIP: Received fragment that claims to be %" SDL_PRIu64 " bytes, expected %i", 2471 header.length, num_bytes - offset); 2472 return; 2473 } 2474 if (header.length > total_length) { 2475 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, 2476 "GIP: Received too long fragment, %" SDL_PRIu64 " bytes, exceeds %d", 2477 header.length, attachment->total_length); 2478 return; 2479 } 2480 attachment->fragment_data = SDL_malloc(attachment->total_length); 2481 SDL_memcpy(attachment->fragment_data, &bytes[offset], (size_t) header.length); 2482 fragment_offset = header.length; 2483 attachment->fragment_offset = (Uint32) fragment_offset; 2484 bytes_remaining = (Uint16) (attachment->total_length - fragment_offset); 2485 } else { 2486 if (header.message_type != attachment->fragment_message) { 2487 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, 2488 "GIP: Received out of sequence message type %02x, expected %02x", 2489 header.message_type, attachment->fragment_message); 2490 GIP_FragmentFailed(attachment, &header); 2491 return; 2492 } 2493 2494 offset += GIP_DecodeLength(&fragment_offset, &bytes[offset], num_bytes - offset); 2495 if (fragment_offset != attachment->fragment_offset) { 2496 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, 2497 "GIP: Received out of sequence fragment, (claimed %" SDL_PRIu64 ", expected %d)", 2498 fragment_offset, attachment->fragment_offset); 2499 GIP_Acknowledge(device, 2500 &header, 2501 attachment->fragment_offset, 2502 (Uint16) (attachment->total_length - attachment->fragment_offset)); 2503 return; 2504 } else if (fragment_offset + header.length > attachment->total_length) { 2505 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, 2506 "GIP: Received too long fragment, %" SDL_PRIu64 " exceeds %d", 2507 fragment_offset + header.length, attachment->total_length); 2508 GIP_FragmentFailed(attachment, &header); 2509 return; 2510 } 2511 2512 bytes_remaining = attachment->total_length - (Uint16) (fragment_offset + header.length); 2513 if (header.length != 0) { 2514 SDL_memcpy(&attachment->fragment_data[fragment_offset], &bytes[offset], (size_t) header.length); 2515 } else { 2516 ok = GIP_HandleMessage(attachment, &header, attachment->fragment_data, attachment->total_length); 2517 if (attachment->fragment_data) { 2518 SDL_free(attachment->fragment_data); 2519 attachment->fragment_data = NULL; 2520 } 2521 attachment->fragment_message = 0; 2522 } 2523 fragment_offset += header.length; 2524 attachment->fragment_offset = (Uint16) fragment_offset; 2525 } 2526 attachment->fragment_timer = SDL_GetTicks(); 2527 } else if (header.length + offset > num_bytes) { 2528 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, 2529 "GIP: Received message with erroneous length (claimed %" SDL_PRIu64 ", actual %d), discarding", 2530 header.length + offset, num_bytes); 2531 return; 2532 } else { 2533 num_bytes -= offset; 2534 bytes += offset; 2535 fragment_offset = header.length; 2536 ok = GIP_HandleMessage(attachment, &header, bytes, num_bytes); 2537 } 2538 2539 if (ok && (header.flags & GIP_FLAG_ACME)) { 2540 GIP_Acknowledge(device, &header, (Uint32) fragment_offset, bytes_remaining); 2541 } 2542} 2543 2544static void HIDAPI_DriverGIP_RumbleSent(void *userdata) 2545{ 2546 GIP_Attachment *ctx = (GIP_Attachment *)userdata; 2547 ctx->rumble_time = SDL_GetTicks(); 2548} 2549 2550static bool HIDAPI_DriverGIP_UpdateRumble(GIP_Attachment *attachment) 2551{ 2552 GIP_DirectMotor motor; 2553 2554 if (!(attachment->features & GIP_FEATURE_MOTOR_CONTROL)) { 2555 return true; 2556 } 2557 2558 if (attachment->rumble_state == GIP_RUMBLE_STATE_QUEUED && attachment->rumble_time) { 2559 attachment->rumble_state = GIP_RUMBLE_STATE_BUSY; 2560 } 2561 2562 if (attachment->rumble_state == GIP_RUMBLE_STATE_BUSY) { 2563 const int RUMBLE_BUSY_TIME_MS = 10; 2564 if (SDL_GetTicks() >= (attachment->rumble_time + RUMBLE_BUSY_TIME_MS)) { 2565 attachment->rumble_time = 0; 2566 attachment->rumble_state = GIP_RUMBLE_STATE_IDLE; 2567 } 2568 } 2569 2570 if (!attachment->rumble_pending) { 2571 return true; 2572 } 2573 2574 if (attachment->rumble_state != GIP_RUMBLE_STATE_IDLE) { 2575 return true; 2576 } 2577 2578 // We're no longer pending, even if we fail to send the rumble below 2579 attachment->rumble_pending = false; 2580 2581 motor.motor_bitmap = GIP_MOTOR_ALL; 2582 motor.left_impulse_level = attachment->left_impulse_level; 2583 motor.right_impulse_level = attachment->right_impulse_level; 2584 motor.left_vibration_level = attachment->left_vibration_level; 2585 motor.right_vibration_level = attachment->right_vibration_level; 2586 motor.duration = SDL_RUMBLE_RESEND_MS / 10 + 5; // Add a 50ms leniency, just in case 2587 motor.delay = 0; 2588 motor.repeat = 0; 2589 2590 Uint8 message[9] = {0}; 2591 SDL_memcpy(&message[1], &motor, sizeof(motor)); 2592 if (!GIP_SendRawMessage(attachment->device, 2593 GIP_CMD_DIRECT_MOTOR, 2594 attachment->attachment_index, 2595 GIP_SequenceNext(attachment, GIP_CMD_DIRECT_MOTOR, false), 2596 message, 2597 sizeof(message), 2598 true, 2599 HIDAPI_DriverGIP_RumbleSent, 2600 attachment)) 2601 { 2602 return SDL_SetError("Couldn't send rumble packet"); 2603 } 2604 2605 attachment->rumble_state = GIP_RUMBLE_STATE_QUEUED; 2606 2607 return true; 2608} 2609 2610static void HIDAPI_DriverGIP_RegisterHints(SDL_HintCallback callback, void *userdata) 2611{ 2612 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_GIP, callback, userdata); 2613 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_GIP_RESET_FOR_METADATA, callback, userdata); 2614} 2615 2616static void HIDAPI_DriverGIP_UnregisterHints(SDL_HintCallback callback, void *userdata) 2617{ 2618 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_GIP, callback, userdata); 2619 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_GIP_RESET_FOR_METADATA, callback, userdata); 2620} 2621 2622static bool HIDAPI_DriverGIP_IsEnabled(void) 2623{ 2624 return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_GIP, 2625 SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE, 2626 SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX, 2627 SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT)))); 2628} 2629 2630static bool HIDAPI_DriverGIP_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol) 2631{ 2632 // Xbox One controllers speak HID over bluetooth instead of GIP 2633 if (device && device->is_bluetooth) { 2634 return false; 2635 } 2636#if defined(SDL_PLATFORM_MACOS) && defined(SDL_JOYSTICK_MFI) 2637 if (!SDL_IsJoystickBluetoothXboxOne(vendor_id, product_id)) { 2638 // On macOS we get a shortened version of the real report and 2639 // you can't write output reports for wired controllers, so 2640 // we'll just use the GCController support instead. 2641 return false; 2642 } 2643#endif 2644 return (type == SDL_GAMEPAD_TYPE_XBOXONE); 2645} 2646 2647static bool HIDAPI_DriverGIP_InitDevice(SDL_HIDAPI_Device *device) 2648{ 2649 GIP_Device *ctx; 2650 GIP_Attachment *attachment; 2651 2652 ctx = (GIP_Device *)SDL_calloc(1, sizeof(*ctx)); 2653 if (!ctx) { 2654 return false; 2655 } 2656 ctx->device = device; 2657 ctx->reset_for_metadata = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_GIP_RESET_FOR_METADATA, false); 2658 2659 attachment = GIP_EnsureAttachment(ctx, 0); 2660 GIP_HandleQuirks(attachment); 2661 2662 if (attachment->quirks & GIP_QUIRK_NO_HELLO) { 2663 ctx->got_hello = true; 2664 GIP_EnsureMetadata(attachment); 2665 } else { 2666 ctx->hello_deadline = SDL_GetTicks() + GIP_HELLO_TIMEOUT; 2667 } 2668 2669 device->context = ctx; 2670 device->type = SDL_GAMEPAD_TYPE_XBOXONE; 2671 2672 return true; 2673} 2674 2675static int HIDAPI_DriverGIP_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id) 2676{ 2677 return -1; 2678} 2679 2680static void HIDAPI_DriverGIP_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) 2681{ 2682} 2683 2684static GIP_Attachment * HIDAPI_DriverGIP_FindAttachment(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 2685{ 2686 GIP_Device *ctx = (GIP_Device *)device->context; 2687 int i; 2688 2689 SDL_AssertJoysticksLocked(); 2690 2691 for (i = 0; i < MAX_ATTACHMENTS; i++) { 2692 if (ctx->attachments[i] && ctx->attachments[i]->joystick == joystick->instance_id) { 2693 return ctx->attachments[i]; 2694 } 2695 } 2696 return NULL; 2697} 2698 2699static bool HIDAPI_DriverGIP_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 2700{ 2701 GIP_Attachment *attachment = HIDAPI_DriverGIP_FindAttachment(device, joystick); 2702 if (!attachment) { 2703 return SDL_SetError("Invalid joystick"); 2704 } 2705 2706 SDL_AssertJoysticksLocked(); 2707 2708 attachment->left_impulse_level = 0; 2709 attachment->right_impulse_level = 0; 2710 attachment->left_vibration_level = 0; 2711 attachment->right_vibration_level = 0; 2712 attachment->rumble_state = GIP_RUMBLE_STATE_IDLE; 2713 attachment->rumble_time = 0; 2714 attachment->rumble_pending = false; 2715 SDL_zeroa(attachment->last_input); 2716 2717 // Initialize the joystick capabilities 2718 joystick->nbuttons = 11; 2719 GIP_EnableEliteButtons(attachment); 2720 if (attachment->xbe_format != GIP_BTN_FMT_UNKNOWN || 2721 (device->vendor_id == USB_VENDOR_MICROSOFT && 2722 device->product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2)) 2723 { 2724 attachment->paddle_idx = (Uint8) joystick->nbuttons; 2725 joystick->nbuttons += 4; 2726 } 2727 if (attachment->features & GIP_FEATURE_CONSOLE_FUNCTION_MAP) { 2728 attachment->share_button_idx = (Uint8) joystick->nbuttons; 2729 joystick->nbuttons++; 2730 } 2731 if (attachment->extra_buttons > 0) { 2732 attachment->extra_button_idx = (Uint8) joystick->nbuttons; 2733 joystick->nbuttons += attachment->extra_buttons; 2734 } 2735 2736 joystick->naxes = SDL_GAMEPAD_AXIS_COUNT; 2737 if (attachment->attachment_type == GIP_TYPE_FLIGHT_STICK) { 2738 /* Flight sticks have at least 4 axes, but only 3 are signed values, so we leave RIGHTY unused */ 2739 joystick->naxes += attachment->extra_axes - 1; 2740 } 2741 2742 joystick->nhats = 1; 2743 2744 return true; 2745} 2746 2747static bool HIDAPI_DriverGIP_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 2748{ 2749 GIP_Attachment *attachment = HIDAPI_DriverGIP_FindAttachment(device, joystick); 2750 if (!attachment) { 2751 return SDL_SetError("Invalid joystick"); 2752 } 2753 2754 if (!(attachment->features & GIP_FEATURE_MOTOR_CONTROL)) { 2755 return SDL_Unsupported(); 2756 } 2757 2758 // Magnitude is 1..100 so scale the 16-bit input here 2759 attachment->left_vibration_level = (Uint8)(low_frequency_rumble / 655); 2760 attachment->right_vibration_level = (Uint8)(high_frequency_rumble / 655); 2761 attachment->rumble_pending = true; 2762 2763 return HIDAPI_DriverGIP_UpdateRumble(attachment); 2764} 2765 2766static bool HIDAPI_DriverGIP_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 2767{ 2768 GIP_Attachment *attachment = HIDAPI_DriverGIP_FindAttachment(device, joystick); 2769 if (!attachment) { 2770 return SDL_SetError("Invalid joystick"); 2771 } 2772 2773 if (!(attachment->features & GIP_FEATURE_MOTOR_CONTROL) || (attachment->quirks & GIP_QUIRK_NO_IMPULSE_VIBRATION)) { 2774 return SDL_Unsupported(); 2775 } 2776 2777 // Magnitude is 1..100 so scale the 16-bit input here 2778 attachment->left_impulse_level = (Uint8)(left_rumble / 655); 2779 attachment->right_impulse_level = (Uint8)(right_rumble / 655); 2780 attachment->rumble_pending = true; 2781 2782 return HIDAPI_DriverGIP_UpdateRumble(attachment); 2783} 2784 2785static Uint32 HIDAPI_DriverGIP_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 2786{ 2787 GIP_Attachment *attachment = HIDAPI_DriverGIP_FindAttachment(device, joystick); 2788 Uint32 result = 0; 2789 if (!attachment) { 2790 return 0; 2791 } 2792 2793 if (attachment->features & GIP_FEATURE_MOTOR_CONTROL) { 2794 result |= SDL_JOYSTICK_CAP_RUMBLE; 2795 if (!(attachment->quirks & GIP_QUIRK_NO_IMPULSE_VIBRATION)) { 2796 result |= SDL_JOYSTICK_CAP_TRIGGER_RUMBLE; 2797 } 2798 } 2799 2800 if (attachment->features & GIP_FEATURE_GUIDE_COLOR) { 2801 result |= SDL_JOYSTICK_CAP_RGB_LED; 2802 } 2803 2804 return result; 2805} 2806 2807static bool HIDAPI_DriverGIP_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 2808{ 2809 GIP_Attachment *attachment = HIDAPI_DriverGIP_FindAttachment(device, joystick); 2810 Uint8 buffer[] = { 0x00, 0x00, 0x00, 0x00, 0x00 }; 2811 2812 if (!attachment) { 2813 return SDL_SetError("Invalid joystick"); 2814 } 2815 2816 if (!(attachment->features & GIP_FEATURE_GUIDE_COLOR)) { 2817 return SDL_Unsupported(); 2818 } 2819 2820 buffer[1] = 0x00; // Whiteness? Sets white intensity when RGB is 0, seems additive 2821 buffer[2] = red; 2822 buffer[3] = green; 2823 buffer[4] = blue; 2824 2825 if (!GIP_SendVendorMessage(attachment, GIP_CMD_GUIDE_COLOR, 0, buffer, sizeof(buffer))) { 2826 return SDL_SetError("Couldn't send LED packet"); 2827 } 2828 return true; 2829} 2830 2831static bool HIDAPI_DriverGIP_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size) 2832{ 2833 return SDL_Unsupported(); 2834} 2835 2836 2837static bool HIDAPI_DriverGIP_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled) 2838{ 2839 return SDL_Unsupported(); 2840} 2841 2842static bool HIDAPI_DriverGIP_UpdateDevice(SDL_HIDAPI_Device *device) 2843{ 2844 GIP_Device *ctx = (GIP_Device *)device->context; 2845 Uint8 bytes[USB_PACKET_LENGTH]; 2846 int i; 2847 int num_bytes; 2848 bool perform_reset = false; 2849 Uint64 timestamp; 2850 2851 while ((num_bytes = SDL_hid_read_timeout(device->dev, bytes, sizeof(bytes), ctx->timeout)) > 0) { 2852 ctx->timeout = 0; 2853 GIP_ReceivePacket(ctx, bytes, num_bytes); 2854 } 2855 2856 timestamp = SDL_GetTicks(); 2857 if (ctx->hello_deadline && timestamp >= ctx->hello_deadline) { 2858 ctx->hello_deadline = 0; 2859 perform_reset = true; 2860 } 2861 for (i = 0; i < MAX_ATTACHMENTS; i++) { 2862 GIP_Attachment *attachment = ctx->attachments[i]; 2863 if (!attachment) { 2864 continue; 2865 } 2866 if (attachment->fragment_message && timestamp >= attachment->fragment_timer + 1000) { 2867 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "GIP: Reliable message transfer failed"); 2868 attachment->fragment_message = 0; 2869 } 2870 if (!perform_reset && 2871 attachment->got_metadata == GIP_METADATA_PENDING && 2872 timestamp >= attachment->metadata_next && 2873 attachment->fragment_message != GIP_CMD_METADATA) 2874 { 2875 if (attachment->metadata_retries < 3) { 2876 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "GIP: Retrying metadata request"); 2877 attachment->metadata_retries++; 2878 attachment->metadata_next = timestamp + 500; 2879 GIP_SendSystemMessage(attachment, GIP_CMD_METADATA, 0, NULL, 0); 2880 } else { 2881 perform_reset = true; 2882 } 2883 } 2884 if (perform_reset) { 2885 if (ctx->reset_for_metadata) { 2886 GIP_SendSetDeviceState(attachment, GIP_STATE_RESET); 2887 } else { 2888 GIP_SetMetadataDefaults(attachment); 2889 GIP_SendInitSequence(attachment); 2890 } 2891 perform_reset = false; 2892 } 2893 HIDAPI_DriverGIP_UpdateRumble(attachment); 2894 } 2895 2896 if (num_bytes < 0 && device->num_joysticks > 0) { 2897 // Read error, device is disconnected 2898 for (i = 0; i < MAX_ATTACHMENTS; i++) { 2899 GIP_Attachment *attachment = ctx->attachments[i]; 2900 if (attachment) { 2901 HIDAPI_JoystickDisconnected(device, attachment->joystick); 2902 } 2903 } 2904 } 2905 return (num_bytes >= 0); 2906} 2907static void HIDAPI_DriverGIP_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 2908{ 2909} 2910 2911static void HIDAPI_DriverGIP_FreeDevice(SDL_HIDAPI_Device *device) 2912{ 2913 GIP_Device *context = (GIP_Device *)device->context; 2914 int i; 2915 2916 for (i = 0; i < MAX_ATTACHMENTS; i++) { 2917 GIP_Attachment *attachment = context->attachments[i]; 2918 if (!attachment) { 2919 continue; 2920 } 2921 if (attachment->fragment_data) { 2922 SDL_free(attachment->fragment_data); 2923 attachment->fragment_data = NULL; 2924 } 2925 if (attachment->keyboard) { 2926 SDL_RemoveKeyboard(attachment->keyboard); 2927 } 2928 GIP_MetadataFree(&attachment->metadata); 2929 SDL_free(attachment); 2930 context->attachments[i] = NULL; 2931 } 2932} 2933 2934SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGIP = { 2935 SDL_HINT_JOYSTICK_HIDAPI_GIP, 2936 true, 2937 HIDAPI_DriverGIP_RegisterHints, 2938 HIDAPI_DriverGIP_UnregisterHints, 2939 HIDAPI_DriverGIP_IsEnabled, 2940 HIDAPI_DriverGIP_IsSupportedDevice, 2941 HIDAPI_DriverGIP_InitDevice, 2942 HIDAPI_DriverGIP_GetDevicePlayerIndex, 2943 HIDAPI_DriverGIP_SetDevicePlayerIndex, 2944 HIDAPI_DriverGIP_UpdateDevice, 2945 HIDAPI_DriverGIP_OpenJoystick, 2946 HIDAPI_DriverGIP_RumbleJoystick, 2947 HIDAPI_DriverGIP_RumbleJoystickTriggers, 2948 HIDAPI_DriverGIP_GetJoystickCapabilities, 2949 HIDAPI_DriverGIP_SetJoystickLED, 2950 HIDAPI_DriverGIP_SendJoystickEffect, 2951 HIDAPI_DriverGIP_SetJoystickSensorsEnabled, 2952 HIDAPI_DriverGIP_CloseJoystick, 2953 HIDAPI_DriverGIP_FreeDevice, 2954}; 2955 2956#endif // SDL_JOYSTICK_HIDAPI_GIP 2957 2958#endif // SDL_JOYSTICK_HIDAPI 2959
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.