1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20 */
21 /* This driver supports both simplified reports and the extended input reports enabled by Steam.
22 Code and logic contributed by Valve Corporation under the SDL zlib license.
23 */
24 #include "../../SDL_internal.h"
25
26 #ifdef SDL_JOYSTICK_HIDAPI
27
28 #include "SDL_hints.h"
29 #include "SDL_events.h"
30 #include "SDL_timer.h"
31 #include "SDL_joystick.h"
32 #include "SDL_gamecontroller.h"
33 #include "../SDL_sysjoystick.h"
34 #include "SDL_hidapijoystick_c.h"
35 #include "SDL_hidapi_rumble.h"
36
37
38 #ifdef SDL_JOYSTICK_HIDAPI_PS4
39
40 typedef enum
41 {
42 k_EPS4ReportIdUsbState = 1,
43 k_EPS4ReportIdUsbEffects = 5,
44 k_EPS4ReportIdBluetoothState = 17,
45 k_EPS4ReportIdBluetoothEffects = 17,
46 k_EPS4ReportIdDisconnectMessage = 226,
47 } EPS4ReportId;
48
49 typedef enum
50 {
51 k_ePS4FeatureReportIdGyroCalibration_USB = 0x02,
52 k_ePS4FeatureReportIdGyroCalibration_BT = 0x05,
53 k_ePS4FeatureReportIdSerialNumber = 0x12,
54 } EPS4FeatureReportID;
55
56 typedef struct
57 {
58 Uint8 ucLeftJoystickX;
59 Uint8 ucLeftJoystickY;
60 Uint8 ucRightJoystickX;
61 Uint8 ucRightJoystickY;
62 Uint8 rgucButtonsHatAndCounter[ 3 ];
63 Uint8 ucTriggerLeft;
64 Uint8 ucTriggerRight;
65 Uint8 _rgucPad0[ 3 ];
66 Sint16 sGyroX;
67 Sint16 sGyroY;
68 Sint16 sGyroZ;
69 Sint16 sAccelX;
70 Sint16 sAccelY;
71 Sint16 sAccelZ;
72 Uint8 _rgucPad1[ 5 ];
73 Uint8 ucBatteryLevel;
74 Uint8 _rgucPad2[ 4 ];
75 Uint8 ucTrackpadCounter1;
76 Uint8 rgucTrackpadData1[ 3 ];
77 Uint8 ucTrackpadCounter2;
78 Uint8 rgucTrackpadData2[ 3 ];
79 } PS4StatePacket_t;
80
81 typedef struct
82 {
83 Uint8 ucRumbleRight;
84 Uint8 ucRumbleLeft;
85 Uint8 ucLedRed;
86 Uint8 ucLedGreen;
87 Uint8 ucLedBlue;
88 Uint8 ucLedDelayOn;
89 Uint8 ucLedDelayOff;
90 Uint8 _rgucPad0[ 8 ];
91 Uint8 ucVolumeLeft;
92 Uint8 ucVolumeRight;
93 Uint8 ucVolumeMic;
94 Uint8 ucVolumeSpeaker;
95 } DS4EffectsState_t;
96
97 typedef struct {
98 SDL_bool is_dongle;
99 SDL_bool is_bluetooth;
100 SDL_bool audio_supported;
101 SDL_bool rumble_supported;
102 int player_index;
103 Uint8 volume;
104 Uint32 last_volume_check;
105 PS4StatePacket_t last_state;
106 } SDL_DriverPS4_Context;
107
108
109 /* Public domain CRC implementation adapted from:
110 http://home.thep.lu.se/~bjorn/crc/crc32_simple.c
111 */
crc32_for_byte(Uint32 r)112 static Uint32 crc32_for_byte(Uint32 r)
113 {
114 int i;
115 for(i = 0; i < 8; ++i) {
116 r = (r & 1? 0: (Uint32)0xEDB88320L) ^ r >> 1;
117 }
118 return r ^ (Uint32)0xFF000000L;
119 }
120
crc32(Uint32 crc,const void * data,int count)121 static Uint32 crc32(Uint32 crc, const void *data, int count)
122 {
123 int i;
124 for(i = 0; i < count; ++i) {
125 crc = crc32_for_byte((Uint8)crc ^ ((const Uint8*)data)[i]) ^ crc >> 8;
126 }
127 return crc;
128 }
129
130 static SDL_bool
HIDAPI_DriverPS4_IsSupportedDevice(const char * name,SDL_GameControllerType type,Uint16 vendor_id,Uint16 product_id,Uint16 version,int interface_number,int interface_class,int interface_subclass,int interface_protocol)131 HIDAPI_DriverPS4_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
132 {
133 return (type == SDL_CONTROLLER_TYPE_PS4);
134 }
135
136 static const char *
HIDAPI_DriverPS4_GetDeviceName(Uint16 vendor_id,Uint16 product_id)137 HIDAPI_DriverPS4_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
138 {
139 if (vendor_id == USB_VENDOR_SONY) {
140 return "PS4 Controller";
141 }
142 return NULL;
143 }
144
ReadFeatureReport(hid_device * dev,Uint8 report_id,Uint8 * data,size_t size)145 static SDL_bool ReadFeatureReport(hid_device *dev, Uint8 report_id, Uint8 *data, size_t size)
146 {
147 Uint8 report[USB_PACKET_LENGTH + 1];
148
149 SDL_memset(report, 0, sizeof(report));
150 report[0] = report_id;
151 if (hid_get_feature_report(dev, report, sizeof(report)) < 0) {
152 return SDL_FALSE;
153 }
154 SDL_memcpy(data, report, SDL_min(size, sizeof(report)));
155 return SDL_TRUE;
156 }
157
CheckUSBConnected(hid_device * dev)158 static SDL_bool CheckUSBConnected(hid_device *dev)
159 {
160 int i;
161 Uint8 data[16];
162
163 /* This will fail if we're on Bluetooth */
164 if (ReadFeatureReport(dev, k_ePS4FeatureReportIdSerialNumber, data, sizeof(data))) {
165 for (i = 0; i < sizeof(data); ++i) {
166 if (data[i] != 0x00) {
167 return SDL_TRUE;
168 }
169 }
170 /* Maybe the dongle without a connected controller? */
171 }
172 return SDL_FALSE;
173 }
174
HIDAPI_DriverPS4_CanRumble(Uint16 vendor_id,Uint16 product_id)175 static SDL_bool HIDAPI_DriverPS4_CanRumble(Uint16 vendor_id, Uint16 product_id)
176 {
177 /* The Razer Panthera fight stick hangs when trying to rumble */
178 if (vendor_id == USB_VENDOR_RAZER &&
179 (product_id == USB_PRODUCT_RAZER_PANTHERA || product_id == USB_PRODUCT_RAZER_PANTHERA_EVO)) {
180 return SDL_FALSE;
181 }
182 return SDL_TRUE;
183 }
184
185 static void
SetLedsForPlayerIndex(DS4EffectsState_t * effects,int player_index)186 SetLedsForPlayerIndex(DS4EffectsState_t *effects, int player_index)
187 {
188 /* This list is the same as what hid-sony.c uses in the Linux kernel.
189 The first 4 values correspond to what the PS4 assigns.
190 */
191 static const Uint8 colors[7][3] = {
192 { 0x00, 0x00, 0x40 }, /* Blue */
193 { 0x40, 0x00, 0x00 }, /* Red */
194 { 0x00, 0x40, 0x00 }, /* Green */
195 { 0x20, 0x00, 0x20 }, /* Pink */
196 { 0x02, 0x01, 0x00 }, /* Orange */
197 { 0x00, 0x01, 0x01 }, /* Teal */
198 { 0x01, 0x01, 0x01 } /* White */
199 };
200
201 if (player_index >= 0) {
202 player_index %= SDL_arraysize(colors);
203 } else {
204 player_index = 0;
205 }
206
207 effects->ucLedRed = colors[player_index][0];
208 effects->ucLedGreen = colors[player_index][1];
209 effects->ucLedBlue = colors[player_index][2];
210 }
211
212 static SDL_bool
HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device * device)213 HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
214 {
215 return HIDAPI_JoystickConnected(device, NULL, SDL_FALSE);
216 }
217
218 static int
HIDAPI_DriverPS4_GetDevicePlayerIndex(SDL_HIDAPI_Device * device,SDL_JoystickID instance_id)219 HIDAPI_DriverPS4_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
220 {
221 return -1;
222 }
223
224 static int HIDAPI_DriverPS4_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble);
225
226 static void
HIDAPI_DriverPS4_SetDevicePlayerIndex(SDL_HIDAPI_Device * device,SDL_JoystickID instance_id,int player_index)227 HIDAPI_DriverPS4_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
228 {
229 SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
230
231 if (!ctx) {
232 return;
233 }
234
235 ctx->player_index = player_index;
236
237 /* This will set the new LED state based on the new player index */
238 HIDAPI_DriverPS4_RumbleJoystick(device, SDL_JoystickFromInstanceID(instance_id), 0, 0);
239 }
240
241 static SDL_bool
HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)242 HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
243 {
244 SDL_DriverPS4_Context *ctx;
245
246 ctx = (SDL_DriverPS4_Context *)SDL_calloc(1, sizeof(*ctx));
247 if (!ctx) {
248 SDL_OutOfMemory();
249 return SDL_FALSE;
250 }
251
252 device->dev = hid_open_path(device->path, 0);
253 if (!device->dev) {
254 SDL_free(ctx);
255 SDL_SetError("Couldn't open %s", device->path);
256 return SDL_FALSE;
257 }
258 device->context = ctx;
259
260 /* Check for type of connection */
261 ctx->is_dongle = (device->vendor_id == USB_VENDOR_SONY && device->product_id == USB_PRODUCT_SONY_DS4_DONGLE);
262 if (ctx->is_dongle) {
263 ctx->is_bluetooth = SDL_FALSE;
264 } else if (device->vendor_id == USB_VENDOR_SONY) {
265 ctx->is_bluetooth = !CheckUSBConnected(device->dev);
266 } else {
267 /* Third party controllers appear to all be wired */
268 ctx->is_bluetooth = SDL_FALSE;
269 }
270 #ifdef DEBUG_PS4
271 SDL_Log("PS4 dongle = %s, bluetooth = %s\n", ctx->is_dongle ? "TRUE" : "FALSE", ctx->is_bluetooth ? "TRUE" : "FALSE");
272 #endif
273
274 /* Check to see if audio is supported */
275 if (device->vendor_id == USB_VENDOR_SONY &&
276 (device->product_id == USB_PRODUCT_SONY_DS4_SLIM || device->product_id == USB_PRODUCT_SONY_DS4_DONGLE)) {
277 ctx->audio_supported = SDL_TRUE;
278 }
279
280 if (HIDAPI_DriverPS4_CanRumble(device->vendor_id, device->product_id)) {
281 if (ctx->is_bluetooth) {
282 ctx->rumble_supported = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, SDL_FALSE);
283 } else {
284 ctx->rumble_supported = SDL_TRUE;
285 }
286 }
287
288 /* Initialize player index (needed for setting LEDs) */
289 ctx->player_index = SDL_JoystickGetPlayerIndex(joystick);
290
291 /* Initialize LED and effect state */
292 HIDAPI_DriverPS4_RumbleJoystick(device, joystick, 0, 0);
293
294 /* Initialize the joystick capabilities */
295 joystick->nbuttons = 16;
296 joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
297 joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
298
299 return SDL_TRUE;
300 }
301
302 static int
HIDAPI_DriverPS4_RumbleJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint16 low_frequency_rumble,Uint16 high_frequency_rumble)303 HIDAPI_DriverPS4_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
304 {
305 SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
306 DS4EffectsState_t *effects;
307 Uint8 data[78];
308 int report_size, offset;
309
310 if (!ctx->rumble_supported) {
311 return SDL_Unsupported();
312 }
313
314 /* In order to send rumble, we have to send a complete effect packet */
315 SDL_memset(data, 0, sizeof(data));
316
317 if (ctx->is_bluetooth) {
318 data[0] = k_EPS4ReportIdBluetoothEffects;
319 data[1] = 0xC0 | 0x04; /* Magic value HID + CRC, also sets interval to 4ms for samples */
320 data[3] = 0x03; /* 0x1 is rumble, 0x2 is lightbar, 0x4 is the blink interval */
321
322 report_size = 78;
323 offset = 6;
324 } else {
325 data[0] = k_EPS4ReportIdUsbEffects;
326 data[1] = 0x07; /* Magic value */
327
328 report_size = 32;
329 offset = 4;
330 }
331 effects = (DS4EffectsState_t *)&data[offset];
332
333 effects->ucRumbleLeft = (low_frequency_rumble >> 8);
334 effects->ucRumbleRight = (high_frequency_rumble >> 8);
335
336 /* Populate the LED state with the appropriate color from our lookup table */
337 SetLedsForPlayerIndex(effects, ctx->player_index);
338
339 if (ctx->is_bluetooth) {
340 /* Bluetooth reports need a CRC at the end of the packet (at least on Linux) */
341 Uint8 ubHdr = 0xA2; /* hidp header is part of the CRC calculation */
342 Uint32 unCRC;
343 unCRC = crc32(0, &ubHdr, 1);
344 unCRC = crc32(unCRC, data, (Uint32)(report_size - sizeof(unCRC)));
345 SDL_memcpy(&data[report_size - sizeof(unCRC)], &unCRC, sizeof(unCRC));
346 }
347
348 if (SDL_HIDAPI_SendRumble(device, data, report_size) != report_size) {
349 return SDL_SetError("Couldn't send rumble packet");
350 }
351 return 0;
352 }
353
354 static void
HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick * joystick,hid_device * dev,SDL_DriverPS4_Context * ctx,PS4StatePacket_t * packet)355 HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverPS4_Context *ctx, PS4StatePacket_t *packet)
356 {
357 Sint16 axis;
358
359 if (ctx->last_state.rgucButtonsHatAndCounter[0] != packet->rgucButtonsHatAndCounter[0]) {
360 {
361 Uint8 data = (packet->rgucButtonsHatAndCounter[0] >> 4);
362
363 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
364 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
365 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
366 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
367 }
368 {
369 Uint8 data = (packet->rgucButtonsHatAndCounter[0] & 0x0F);
370 SDL_bool dpad_up = SDL_FALSE;
371 SDL_bool dpad_down = SDL_FALSE;
372 SDL_bool dpad_left = SDL_FALSE;
373 SDL_bool dpad_right = SDL_FALSE;
374
375 switch (data) {
376 case 0:
377 dpad_up = SDL_TRUE;
378 break;
379 case 1:
380 dpad_up = SDL_TRUE;
381 dpad_right = SDL_TRUE;
382 break;
383 case 2:
384 dpad_right = SDL_TRUE;
385 break;
386 case 3:
387 dpad_right = SDL_TRUE;
388 dpad_down = SDL_TRUE;
389 break;
390 case 4:
391 dpad_down = SDL_TRUE;
392 break;
393 case 5:
394 dpad_left = SDL_TRUE;
395 dpad_down = SDL_TRUE;
396 break;
397 case 6:
398 dpad_left = SDL_TRUE;
399 break;
400 case 7:
401 dpad_up = SDL_TRUE;
402 dpad_left = SDL_TRUE;
403 break;
404 default:
405 break;
406 }
407 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
408 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
409 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
410 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
411 }
412 }
413
414 if (ctx->last_state.rgucButtonsHatAndCounter[1] != packet->rgucButtonsHatAndCounter[1]) {
415 Uint8 data = packet->rgucButtonsHatAndCounter[1];
416
417 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
418 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
419 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
420 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
421 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED);
422 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x80) ? SDL_PRESSED : SDL_RELEASED);
423 }
424
425 /* Some fightsticks, ex: Victrix FS Pro will only this these digital trigger bits and not the analog values so this needs to run whenever the
426 trigger is evaluated
427 */
428 if ((packet->rgucButtonsHatAndCounter[1] & 0x0C) != 0) {
429 Uint8 data = packet->rgucButtonsHatAndCounter[1];
430 packet->ucTriggerLeft = (data & 0x04) && packet->ucTriggerLeft == 0 ? 255 : packet->ucTriggerLeft;
431 packet->ucTriggerRight = (data & 0x08) && packet->ucTriggerRight == 0 ? 255 : packet->ucTriggerRight;
432 }
433
434 if (ctx->last_state.rgucButtonsHatAndCounter[2] != packet->rgucButtonsHatAndCounter[2]) {
435 Uint8 data = (packet->rgucButtonsHatAndCounter[2] & 0x03);
436
437 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
438 SDL_PrivateJoystickButton(joystick, 15, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
439 }
440
441 axis = ((int)packet->ucTriggerLeft * 257) - 32768;
442 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
443 axis = ((int)packet->ucTriggerRight * 257) - 32768;
444 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
445 axis = ((int)packet->ucLeftJoystickX * 257) - 32768;
446 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
447 axis = ((int)packet->ucLeftJoystickY * 257) - 32768;
448 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
449 axis = ((int)packet->ucRightJoystickX * 257) - 32768;
450 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
451 axis = ((int)packet->ucRightJoystickY * 257) - 32768;
452 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
453
454 if (packet->ucBatteryLevel & 0x10) {
455 joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
456 } else {
457 /* Battery level ranges from 0 to 10 */
458 int level = (packet->ucBatteryLevel & 0xF);
459 if (level == 0) {
460 joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY;
461 } else if (level <= 2) {
462 joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW;
463 } else if (level <= 7) {
464 joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM;
465 } else {
466 joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
467 }
468 }
469
470 SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state));
471 }
472
473 static SDL_bool
HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device * device)474 HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
475 {
476 SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
477 SDL_Joystick *joystick = NULL;
478 Uint8 data[USB_PACKET_LENGTH];
479 int size;
480
481 if (device->num_joysticks > 0) {
482 joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
483 }
484 if (!joystick) {
485 return SDL_FALSE;
486 }
487
488 while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
489 switch (data[0]) {
490 case k_EPS4ReportIdUsbState:
491 HIDAPI_DriverPS4_HandleStatePacket(joystick, device->dev, ctx, (PS4StatePacket_t *)&data[1]);
492 break;
493 case k_EPS4ReportIdBluetoothState:
494 /* Bluetooth state packets have two additional bytes at the beginning */
495 HIDAPI_DriverPS4_HandleStatePacket(joystick, device->dev, ctx, (PS4StatePacket_t *)&data[3]);
496 break;
497 default:
498 #ifdef DEBUG_JOYSTICK
499 SDL_Log("Unknown PS4 packet: 0x%.2x\n", data[0]);
500 #endif
501 break;
502 }
503 }
504
505 if (size < 0) {
506 /* Read error, device is disconnected */
507 HIDAPI_JoystickDisconnected(device, joystick->instance_id, SDL_FALSE);
508 }
509 return (size >= 0);
510 }
511
512 static void
HIDAPI_DriverPS4_CloseJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)513 HIDAPI_DriverPS4_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
514 {
515 hid_close(device->dev);
516 device->dev = NULL;
517
518 SDL_free(device->context);
519 device->context = NULL;
520 }
521
522 static void
HIDAPI_DriverPS4_FreeDevice(SDL_HIDAPI_Device * device)523 HIDAPI_DriverPS4_FreeDevice(SDL_HIDAPI_Device *device)
524 {
525 }
526
527 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4 =
528 {
529 SDL_HINT_JOYSTICK_HIDAPI_PS4,
530 SDL_TRUE,
531 HIDAPI_DriverPS4_IsSupportedDevice,
532 HIDAPI_DriverPS4_GetDeviceName,
533 HIDAPI_DriverPS4_InitDevice,
534 HIDAPI_DriverPS4_GetDevicePlayerIndex,
535 HIDAPI_DriverPS4_SetDevicePlayerIndex,
536 HIDAPI_DriverPS4_UpdateDevice,
537 HIDAPI_DriverPS4_OpenJoystick,
538 HIDAPI_DriverPS4_RumbleJoystick,
539 HIDAPI_DriverPS4_CloseJoystick,
540 HIDAPI_DriverPS4_FreeDevice,
541 NULL
542 };
543
544 #endif /* SDL_JOYSTICK_HIDAPI_PS4 */
545
546 #endif /* SDL_JOYSTICK_HIDAPI */
547
548 /* vi: set ts=4 sw=4 expandtab: */
549