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