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 the Nintendo Switch Pro controller.
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_hints_c.h"
34 #include "../SDL_sysjoystick.h"
35 #include "SDL_hidapijoystick_c.h"
36 #include "SDL_hidapi_rumble.h"
37 
38 
39 #ifdef SDL_JOYSTICK_HIDAPI_SWITCH
40 
41 /* Define this to get log output for rumble logic */
42 /*#define DEBUG_RUMBLE*/
43 
44 /* How often you can write rumble commands to the controller in Bluetooth mode
45    If you send commands more frequently than this, you can turn off the controller.
46  */
47 #define RUMBLE_WRITE_FREQUENCY_MS   25
48 
49 /* How often you have to refresh a long duration rumble to keep the motors running */
50 #define RUMBLE_REFRESH_FREQUENCY_MS 40
51 
52 typedef enum {
53     k_eSwitchInputReportIDs_SubcommandReply       = 0x21,
54     k_eSwitchInputReportIDs_FullControllerState   = 0x30,
55     k_eSwitchInputReportIDs_SimpleControllerState = 0x3F,
56     k_eSwitchInputReportIDs_CommandAck            = 0x81,
57 } ESwitchInputReportIDs;
58 
59 typedef enum {
60     k_eSwitchOutputReportIDs_RumbleAndSubcommand = 0x01,
61     k_eSwitchOutputReportIDs_Rumble              = 0x10,
62     k_eSwitchOutputReportIDs_Proprietary         = 0x80,
63 } ESwitchOutputReportIDs;
64 
65 typedef enum {
66     k_eSwitchSubcommandIDs_BluetoothManualPair = 0x01,
67     k_eSwitchSubcommandIDs_RequestDeviceInfo   = 0x02,
68     k_eSwitchSubcommandIDs_SetInputReportMode  = 0x03,
69     k_eSwitchSubcommandIDs_SetHCIState         = 0x06,
70     k_eSwitchSubcommandIDs_SPIFlashRead        = 0x10,
71     k_eSwitchSubcommandIDs_SetPlayerLights     = 0x30,
72     k_eSwitchSubcommandIDs_SetHomeLight        = 0x38,
73     k_eSwitchSubcommandIDs_EnableIMU           = 0x40,
74     k_eSwitchSubcommandIDs_SetIMUSensitivity   = 0x41,
75     k_eSwitchSubcommandIDs_EnableVibration     = 0x48,
76 } ESwitchSubcommandIDs;
77 
78 typedef enum {
79     k_eSwitchProprietaryCommandIDs_Handshake = 0x02,
80     k_eSwitchProprietaryCommandIDs_HighSpeed = 0x03,
81     k_eSwitchProprietaryCommandIDs_ForceUSB  = 0x04,
82     k_eSwitchProprietaryCommandIDs_ClearUSB  = 0x05,
83     k_eSwitchProprietaryCommandIDs_ResetMCU  = 0x06,
84 } ESwitchProprietaryCommandIDs;
85 
86 typedef enum {
87     k_eSwitchDeviceInfoControllerType_JoyConLeft     = 0x1,
88     k_eSwitchDeviceInfoControllerType_JoyConRight    = 0x2,
89     k_eSwitchDeviceInfoControllerType_ProController  = 0x3,
90 } ESwitchDeviceInfoControllerType;
91 
92 #define k_unSwitchOutputPacketDataLength 49
93 #define k_unSwitchMaxOutputPacketLength  64
94 #define k_unSwitchBluetoothPacketLength  k_unSwitchOutputPacketDataLength
95 #define k_unSwitchUSBPacketLength        k_unSwitchMaxOutputPacketLength
96 
97 #define k_unSPIStickCalibrationStartOffset  0x603D
98 #define k_unSPIStickCalibrationEndOffset    0x604E
99 #define k_unSPIStickCalibrationLength       (k_unSPIStickCalibrationEndOffset - k_unSPIStickCalibrationStartOffset + 1)
100 
101 #pragma pack(1)
102 typedef struct
103 {
104     Uint8 rgucButtons[2];
105     Uint8 ucStickHat;
106     Uint8 rgucJoystickLeft[2];
107     Uint8 rgucJoystickRight[2];
108 } SwitchInputOnlyControllerStatePacket_t;
109 
110 typedef struct
111 {
112     Uint8 rgucButtons[2];
113     Uint8 ucStickHat;
114     Sint16 sJoystickLeft[2];
115     Sint16 sJoystickRight[2];
116 } SwitchSimpleStatePacket_t;
117 
118 typedef struct
119 {
120     Uint8 ucCounter;
121     Uint8 ucBatteryAndConnection;
122     Uint8 rgucButtons[3];
123     Uint8 rgucJoystickLeft[3];
124     Uint8 rgucJoystickRight[3];
125     Uint8 ucVibrationCode;
126 } SwitchControllerStatePacket_t;
127 
128 typedef struct
129 {
130     SwitchControllerStatePacket_t controllerState;
131 
132     struct {
133         Sint16 sAccelX;
134         Sint16 sAccelY;
135         Sint16 sAccelZ;
136 
137         Sint16 sGyroX;
138         Sint16 sGyroY;
139         Sint16 sGyroZ;
140     } imuState[3];
141 } SwitchStatePacket_t;
142 
143 typedef struct
144 {
145     Uint32 unAddress;
146     Uint8 ucLength;
147 } SwitchSPIOpData_t;
148 
149 typedef struct
150 {
151     SwitchControllerStatePacket_t m_controllerState;
152 
153     Uint8 ucSubcommandAck;
154     Uint8 ucSubcommandID;
155 
156     #define k_unSubcommandDataBytes 35
157     union {
158         Uint8 rgucSubcommandData[k_unSubcommandDataBytes];
159 
160         struct {
161             SwitchSPIOpData_t opData;
162             Uint8 rgucReadData[k_unSubcommandDataBytes - sizeof(SwitchSPIOpData_t)];
163         } spiReadData;
164 
165         struct {
166             Uint8 rgucFirmwareVersion[2];
167             Uint8 ucDeviceType;
168             Uint8 ucFiller1;
169             Uint8 rgucMACAddress[6];
170             Uint8 ucFiller2;
171             Uint8 ucColorLocation;
172         } deviceInfo;
173     };
174 } SwitchSubcommandInputPacket_t;
175 
176 typedef struct
177 {
178     Uint8 rgucData[4];
179 } SwitchRumbleData_t;
180 
181 typedef struct
182 {
183     Uint8 ucPacketType;
184     Uint8 ucPacketNumber;
185     SwitchRumbleData_t rumbleData[2];
186 } SwitchCommonOutputPacket_t;
187 
188 typedef struct
189 {
190     SwitchCommonOutputPacket_t commonData;
191 
192     Uint8 ucSubcommandID;
193     Uint8 rgucSubcommandData[k_unSwitchOutputPacketDataLength - sizeof(SwitchCommonOutputPacket_t) - 1];
194 } SwitchSubcommandOutputPacket_t;
195 
196 typedef struct
197 {
198     Uint8 ucPacketType;
199     Uint8 ucProprietaryID;
200 
201     Uint8 rgucProprietaryData[k_unSwitchOutputPacketDataLength - 1 - 1];
202 } SwitchProprietaryOutputPacket_t;
203 #pragma pack()
204 
205 typedef struct {
206     SDL_HIDAPI_Device *device;
207     SDL_bool m_bInputOnly;
208     SDL_bool m_bHasHomeLED;
209     SDL_bool m_bUsingBluetooth;
210     SDL_bool m_bIsGameCube;
211     SDL_bool m_bUseButtonLabels;
212     Uint8 m_nCommandNumber;
213     SwitchCommonOutputPacket_t m_RumblePacket;
214     Uint8 m_rgucReadBuffer[k_unSwitchMaxOutputPacketLength];
215     SDL_bool m_bRumbleActive;
216     Uint32 m_unRumbleSent;
217     SDL_bool m_bRumblePending;
218     SDL_bool m_bRumbleZeroPending;
219     Uint32 m_unRumblePending;
220 
221     SwitchInputOnlyControllerStatePacket_t m_lastInputOnlyState;
222     SwitchSimpleStatePacket_t m_lastSimpleState;
223     SwitchStatePacket_t m_lastFullState;
224 
225     struct StickCalibrationData {
226         struct {
227             Sint16 sCenter;
228             Sint16 sMin;
229             Sint16 sMax;
230         } axis[2];
231     } m_StickCalData[2];
232 
233     struct StickExtents {
234         struct {
235             Sint16 sMin;
236             Sint16 sMax;
237         } axis[2];
238     } m_StickExtents[2];
239 } SDL_DriverSwitch_Context;
240 
241 
242 static SDL_bool
HasHomeLED(int vendor_id,int product_id)243 HasHomeLED(int vendor_id, int product_id)
244 {
245     /* The Power A Nintendo Switch Pro controllers don't have a Home LED */
246     if (vendor_id == 0 && product_id == 0) {
247         return SDL_FALSE;
248     }
249 
250     /* HORI Wireless Switch Pad */
251     if (vendor_id == 0x0f0d && product_id == 0x00f6) {
252         return SDL_FALSE;
253     }
254 
255     return SDL_TRUE;
256 }
257 
258 static SDL_bool
IsGameCubeFormFactor(int vendor_id,int product_id)259 IsGameCubeFormFactor(int vendor_id, int product_id)
260 {
261     static Uint32 gamecube_formfactor[] = {
262         MAKE_VIDPID(0x0e6f, 0x0185),    /* PDP Wired Fight Pad Pro for Nintendo Switch */
263         MAKE_VIDPID(0x20d6, 0xa711),    /* Core (Plus) Wired Controller */
264     };
265     Uint32 id = MAKE_VIDPID(vendor_id, product_id);
266     int i;
267 
268     for (i = 0; i < SDL_arraysize(gamecube_formfactor); ++i) {
269         if (id == gamecube_formfactor[i]) {
270             return SDL_TRUE;
271         }
272     }
273     return SDL_FALSE;
274 }
275 
276 static SDL_bool
HIDAPI_DriverSwitch_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)277 HIDAPI_DriverSwitch_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)
278 {
279     /* The HORI Wireless Switch Pad enumerates as a HID device when connected via USB
280        with the same VID/PID as when connected over Bluetooth but doesn't actually
281        support communication over USB. The most reliable way to block this without allowing the
282        controller to continually attempt to reconnect is to filter it out by manufactuer/product string.
283        Note that the controller does have a different product string when connected over Bluetooth.
284      */
285     if (SDL_strcmp( name, "HORI Wireless Switch Pad" ) == 0) {
286         return SDL_FALSE;
287     }
288     return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO);
289 }
290 
291 static const char *
HIDAPI_DriverSwitch_GetDeviceName(Uint16 vendor_id,Uint16 product_id)292 HIDAPI_DriverSwitch_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
293 {
294     /* Give a user friendly name for this controller */
295     return "Nintendo Switch Pro Controller";
296 }
297 
ReadInput(SDL_DriverSwitch_Context * ctx)298 static int ReadInput(SDL_DriverSwitch_Context *ctx)
299 {
300     /* Make sure we don't try to read at the same time a write is happening */
301     if (SDL_AtomicGet(&ctx->device->rumble_pending) > 0) {
302         return 0;
303     }
304 
305     return hid_read_timeout(ctx->device->dev, ctx->m_rgucReadBuffer, sizeof(ctx->m_rgucReadBuffer), 0);
306 }
307 
WriteOutput(SDL_DriverSwitch_Context * ctx,const Uint8 * data,int size)308 static int WriteOutput(SDL_DriverSwitch_Context *ctx, const Uint8 *data, int size)
309 {
310     /* Use the rumble thread for general asynchronous writes */
311     if (SDL_HIDAPI_LockRumble() < 0) {
312         return -1;
313     }
314     return SDL_HIDAPI_SendRumbleAndUnlock(ctx->device, data, size);
315 }
316 
ReadSubcommandReply(SDL_DriverSwitch_Context * ctx,ESwitchSubcommandIDs expectedID)317 static SwitchSubcommandInputPacket_t *ReadSubcommandReply(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs expectedID)
318 {
319     /* Average response time for messages is ~30ms */
320     Uint32 TimeoutMs = 100;
321     Uint32 startTicks = SDL_GetTicks();
322 
323     int nRead = 0;
324     while ((nRead = ReadInput(ctx)) != -1) {
325         if (nRead > 0) {
326             if (ctx->m_rgucReadBuffer[0] == k_eSwitchInputReportIDs_SubcommandReply) {
327                 SwitchSubcommandInputPacket_t *reply = (SwitchSubcommandInputPacket_t *)&ctx->m_rgucReadBuffer[1];
328                 if (reply->ucSubcommandID == expectedID && (reply->ucSubcommandAck & 0x80)) {
329                     return reply;
330                 }
331             }
332         } else {
333             SDL_Delay(1);
334         }
335 
336         if (SDL_TICKS_PASSED(SDL_GetTicks(), startTicks + TimeoutMs)) {
337             break;
338         }
339     }
340     return NULL;
341 }
342 
ReadProprietaryReply(SDL_DriverSwitch_Context * ctx,ESwitchProprietaryCommandIDs expectedID)343 static SDL_bool ReadProprietaryReply(SDL_DriverSwitch_Context *ctx, ESwitchProprietaryCommandIDs expectedID)
344 {
345     /* Average response time for messages is ~30ms */
346     Uint32 TimeoutMs = 100;
347     Uint32 startTicks = SDL_GetTicks();
348 
349     int nRead = 0;
350     while ((nRead = ReadInput(ctx)) != -1) {
351         if (nRead > 0) {
352             if (ctx->m_rgucReadBuffer[0] == k_eSwitchInputReportIDs_CommandAck && ctx->m_rgucReadBuffer[1] == expectedID) {
353                 return SDL_TRUE;
354             }
355         } else {
356             SDL_Delay(1);
357         }
358 
359         if (SDL_TICKS_PASSED(SDL_GetTicks(), startTicks + TimeoutMs)) {
360             break;
361         }
362     }
363     return SDL_FALSE;
364 }
365 
ConstructSubcommand(SDL_DriverSwitch_Context * ctx,ESwitchSubcommandIDs ucCommandID,Uint8 * pBuf,Uint8 ucLen,SwitchSubcommandOutputPacket_t * outPacket)366 static void ConstructSubcommand(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs ucCommandID, Uint8 *pBuf, Uint8 ucLen, SwitchSubcommandOutputPacket_t *outPacket)
367 {
368     SDL_memset(outPacket, 0, sizeof(*outPacket));
369 
370     outPacket->commonData.ucPacketType = k_eSwitchOutputReportIDs_RumbleAndSubcommand;
371     outPacket->commonData.ucPacketNumber = ctx->m_nCommandNumber;
372 
373     SDL_memcpy(&outPacket->commonData.rumbleData, &ctx->m_RumblePacket.rumbleData, sizeof(ctx->m_RumblePacket.rumbleData));
374 
375     outPacket->ucSubcommandID = ucCommandID;
376     SDL_memcpy(outPacket->rgucSubcommandData, pBuf, ucLen);
377 
378     ctx->m_nCommandNumber = (ctx->m_nCommandNumber + 1) & 0xF;
379 }
380 
WritePacket(SDL_DriverSwitch_Context * ctx,void * pBuf,Uint8 ucLen)381 static SDL_bool WritePacket(SDL_DriverSwitch_Context *ctx, void *pBuf, Uint8 ucLen)
382 {
383     Uint8 rgucBuf[k_unSwitchMaxOutputPacketLength];
384     const size_t unWriteSize = ctx->m_bUsingBluetooth ? k_unSwitchBluetoothPacketLength : k_unSwitchUSBPacketLength;
385 
386     if (ucLen > k_unSwitchOutputPacketDataLength) {
387         return SDL_FALSE;
388     }
389 
390     if (ucLen < unWriteSize) {
391         SDL_memcpy(rgucBuf, pBuf, ucLen);
392         SDL_memset(rgucBuf+ucLen, 0, unWriteSize-ucLen);
393         pBuf = rgucBuf;
394         ucLen = (Uint8)unWriteSize;
395     }
396     return (WriteOutput(ctx, (Uint8 *)pBuf, ucLen) >= 0);
397 }
398 
WriteSubcommand(SDL_DriverSwitch_Context * ctx,ESwitchSubcommandIDs ucCommandID,Uint8 * pBuf,Uint8 ucLen,SwitchSubcommandInputPacket_t ** ppReply)399 static SDL_bool WriteSubcommand(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs ucCommandID, Uint8 *pBuf, Uint8 ucLen, SwitchSubcommandInputPacket_t **ppReply)
400 {
401     int nRetries = 5;
402     SwitchSubcommandInputPacket_t *reply = NULL;
403 
404     while (!reply && nRetries--) {
405         SwitchSubcommandOutputPacket_t commandPacket;
406         ConstructSubcommand(ctx, ucCommandID, pBuf, ucLen, &commandPacket);
407 
408         if (!WritePacket(ctx, &commandPacket, sizeof(commandPacket))) {
409             continue;
410         }
411 
412         reply = ReadSubcommandReply(ctx, ucCommandID);
413     }
414 
415     if (ppReply) {
416         *ppReply = reply;
417     }
418     return reply != NULL;
419 }
420 
WriteProprietary(SDL_DriverSwitch_Context * ctx,ESwitchProprietaryCommandIDs ucCommand,Uint8 * pBuf,Uint8 ucLen,SDL_bool waitForReply)421 static SDL_bool WriteProprietary(SDL_DriverSwitch_Context *ctx, ESwitchProprietaryCommandIDs ucCommand, Uint8 *pBuf, Uint8 ucLen, SDL_bool waitForReply)
422 {
423     int nRetries = 5;
424 
425     while (nRetries--) {
426         SwitchProprietaryOutputPacket_t packet;
427 
428         if ((!pBuf && ucLen > 0) || ucLen > sizeof(packet.rgucProprietaryData)) {
429             return SDL_FALSE;
430         }
431 
432         packet.ucPacketType = k_eSwitchOutputReportIDs_Proprietary;
433         packet.ucProprietaryID = ucCommand;
434         if (pBuf) {
435             SDL_memcpy(packet.rgucProprietaryData, pBuf, ucLen);
436         }
437 
438         if (!WritePacket(ctx, &packet, sizeof(packet))) {
439             continue;
440         }
441 
442         if (!waitForReply || ReadProprietaryReply(ctx, ucCommand)) {
443             return SDL_TRUE;
444         }
445     }
446     return SDL_FALSE;
447 }
448 
SetNeutralRumble(SwitchRumbleData_t * pRumble)449 static void SetNeutralRumble(SwitchRumbleData_t *pRumble)
450 {
451     pRumble->rgucData[0] = 0x00;
452     pRumble->rgucData[1] = 0x01;
453     pRumble->rgucData[2] = 0x40;
454     pRumble->rgucData[3] = 0x40;
455 }
456 
EncodeRumble(SwitchRumbleData_t * pRumble,Uint16 usHighFreq,Uint8 ucHighFreqAmp,Uint8 ucLowFreq,Uint16 usLowFreqAmp)457 static void EncodeRumble(SwitchRumbleData_t *pRumble, Uint16 usHighFreq, Uint8 ucHighFreqAmp, Uint8 ucLowFreq, Uint16 usLowFreqAmp)
458 {
459     if (ucHighFreqAmp > 0 || usLowFreqAmp > 0) {
460         // High-band frequency and low-band amplitude are actually nine-bits each so they
461         // take a bit from the high-band amplitude and low-band frequency bytes respectively
462         pRumble->rgucData[0] = usHighFreq & 0xFF;
463         pRumble->rgucData[1] = ucHighFreqAmp | ((usHighFreq >> 8) & 0x01);
464 
465         pRumble->rgucData[2]  = ucLowFreq | ((usLowFreqAmp >> 8) & 0x80);
466         pRumble->rgucData[3]  = usLowFreqAmp & 0xFF;
467 
468 #ifdef DEBUG_RUMBLE
469         SDL_Log("Freq: %.2X %.2X  %.2X, Amp: %.2X  %.2X %.2X\n",
470             usHighFreq & 0xFF, ((usHighFreq >> 8) & 0x01), ucLowFreq,
471             ucHighFreqAmp, ((usLowFreqAmp >> 8) & 0x80), usLowFreqAmp & 0xFF);
472 #endif
473     } else {
474         SetNeutralRumble(pRumble);
475     }
476 }
477 
WriteRumble(SDL_DriverSwitch_Context * ctx)478 static SDL_bool WriteRumble(SDL_DriverSwitch_Context *ctx)
479 {
480     /* Write into m_RumblePacket rather than a temporary buffer to allow the current rumble state
481      * to be retained for subsequent rumble or subcommand packets sent to the controller
482      */
483     ctx->m_RumblePacket.ucPacketType = k_eSwitchOutputReportIDs_Rumble;
484     ctx->m_RumblePacket.ucPacketNumber = ctx->m_nCommandNumber;
485     ctx->m_nCommandNumber = (ctx->m_nCommandNumber + 1) & 0xF;
486 
487     /* Refresh the rumble state periodically */
488     ctx->m_unRumbleSent = SDL_GetTicks();
489 
490     return WritePacket(ctx, (Uint8 *)&ctx->m_RumblePacket, sizeof(ctx->m_RumblePacket));
491 }
492 
BTrySetupUSB(SDL_DriverSwitch_Context * ctx)493 static SDL_bool BTrySetupUSB(SDL_DriverSwitch_Context *ctx)
494 {
495     /* We have to send a connection handshake to the controller when communicating over USB
496      * before we're able to send it other commands. Luckily this command is not supported
497      * over Bluetooth, so we can use the controller's lack of response as a way to
498      * determine if the connection is over USB or Bluetooth
499      */
500     if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Handshake, NULL, 0, SDL_TRUE)) {
501         return SDL_FALSE;
502     }
503     if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_HighSpeed, NULL, 0, SDL_TRUE)) {
504         /* The 8BitDo M30 and SF30 Pro don't respond to this command, but otherwise work correctly */
505         /*return SDL_FALSE;*/
506     }
507     if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Handshake, NULL, 0, SDL_TRUE)) {
508         return SDL_FALSE;
509     }
510     return SDL_TRUE;
511 }
512 
SetVibrationEnabled(SDL_DriverSwitch_Context * ctx,Uint8 enabled)513 static SDL_bool SetVibrationEnabled(SDL_DriverSwitch_Context *ctx, Uint8 enabled)
514 {
515     return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_EnableVibration, &enabled, sizeof(enabled), NULL);
516 
517 }
SetInputMode(SDL_DriverSwitch_Context * ctx,Uint8 input_mode)518 static SDL_bool SetInputMode(SDL_DriverSwitch_Context *ctx, Uint8 input_mode)
519 {
520     return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetInputReportMode, &input_mode, 1, NULL);
521 }
522 
SetHomeLED(SDL_DriverSwitch_Context * ctx,Uint8 brightness)523 static SDL_bool SetHomeLED(SDL_DriverSwitch_Context *ctx, Uint8 brightness)
524 {
525     Uint8 ucLedIntensity = 0;
526     Uint8 rgucBuffer[4];
527 
528     if (brightness > 0) {
529         if (brightness < 65) {
530             ucLedIntensity = (brightness + 5) / 10;
531         } else {
532             ucLedIntensity = (Uint8)SDL_ceilf(0xF * SDL_powf((float)brightness / 100.f, 2.13f));
533         }
534     }
535 
536     rgucBuffer[0] = (0x0 << 4) | 0x1;  /* 0 mini cycles (besides first), cycle duration 8ms */
537     rgucBuffer[1] = ((ucLedIntensity & 0xF) << 4) | 0x0;  /* LED start intensity (0x0-0xF), 0 cycles (LED stays on at start intensity after first cycle) */
538     rgucBuffer[2] = ((ucLedIntensity & 0xF) << 4) | 0x0;  /* First cycle LED intensity, 0x0 intensity for second cycle */
539     rgucBuffer[3] = (0x0 << 4) | 0x0;  /* 8ms fade transition to first cycle, 8ms first cycle LED duration */
540 
541     return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetHomeLight, rgucBuffer, sizeof(rgucBuffer), NULL);
542 }
543 
SetSlotLED(SDL_DriverSwitch_Context * ctx,Uint8 slot)544 static SDL_bool SetSlotLED(SDL_DriverSwitch_Context *ctx, Uint8 slot)
545 {
546     Uint8 led_data = (1 << slot);
547     return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetPlayerLights, &led_data, sizeof(led_data), NULL);
548 }
549 
LoadStickCalibration(SDL_DriverSwitch_Context * ctx,Uint8 input_mode)550 static SDL_bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx, Uint8 input_mode)
551 {
552     Uint8 *pStickCal;
553     size_t stick, axis;
554     SwitchSubcommandInputPacket_t *reply = NULL;
555 
556     /* Read Calibration Info */
557     SwitchSPIOpData_t readParams;
558     readParams.unAddress = k_unSPIStickCalibrationStartOffset;
559     readParams.ucLength = k_unSPIStickCalibrationLength;
560 
561     if (!WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (uint8_t *)&readParams, sizeof(readParams), &reply)) {
562         return SDL_FALSE;
563     }
564 
565     /* Stick calibration values are 12-bits each and are packed by bit
566      * For whatever reason the fields are in a different order for each stick
567      * Left:  X-Max, Y-Max, X-Center, Y-Center, X-Min, Y-Min
568      * Right: X-Center, Y-Center, X-Min, Y-Min, X-Max, Y-Max
569      */
570     pStickCal = reply->spiReadData.rgucReadData;
571 
572     /* Left stick */
573     ctx->m_StickCalData[0].axis[0].sMax    = ((pStickCal[1] << 8) & 0xF00) | pStickCal[0];     /* X Axis max above center */
574     ctx->m_StickCalData[0].axis[1].sMax    = (pStickCal[2] << 4) | (pStickCal[1] >> 4);         /* Y Axis max above center */
575     ctx->m_StickCalData[0].axis[0].sCenter = ((pStickCal[4] << 8) & 0xF00) | pStickCal[3];     /* X Axis center */
576     ctx->m_StickCalData[0].axis[1].sCenter = (pStickCal[5] << 4) | (pStickCal[4] >> 4);        /* Y Axis center */
577     ctx->m_StickCalData[0].axis[0].sMin    = ((pStickCal[7] << 8) & 0xF00) | pStickCal[6];      /* X Axis min below center */
578     ctx->m_StickCalData[0].axis[1].sMin    = (pStickCal[8] << 4) | (pStickCal[7] >> 4);        /* Y Axis min below center */
579 
580     /* Right stick */
581     ctx->m_StickCalData[1].axis[0].sCenter = ((pStickCal[10] << 8) & 0xF00) | pStickCal[9];     /* X Axis center */
582     ctx->m_StickCalData[1].axis[1].sCenter = (pStickCal[11] << 4) | (pStickCal[10] >> 4);      /* Y Axis center */
583     ctx->m_StickCalData[1].axis[0].sMin    = ((pStickCal[13] << 8) & 0xF00) | pStickCal[12];    /* X Axis min below center */
584     ctx->m_StickCalData[1].axis[1].sMin    = (pStickCal[14] << 4) | (pStickCal[13] >> 4);      /* Y Axis min below center */
585     ctx->m_StickCalData[1].axis[0].sMax    = ((pStickCal[16] << 8) & 0xF00) | pStickCal[15];    /* X Axis max above center */
586     ctx->m_StickCalData[1].axis[1].sMax    = (pStickCal[17] << 4) | (pStickCal[16] >> 4);      /* Y Axis max above center */
587 
588     /* Filter out any values that were uninitialized (0xFFF) in the SPI read */
589     for (stick = 0; stick < 2; ++stick) {
590         for (axis = 0; axis < 2; ++axis) {
591             if (ctx->m_StickCalData[stick].axis[axis].sCenter == 0xFFF) {
592                 ctx->m_StickCalData[stick].axis[axis].sCenter = 0;
593             }
594             if (ctx->m_StickCalData[stick].axis[axis].sMax == 0xFFF) {
595                 ctx->m_StickCalData[stick].axis[axis].sMax = 0;
596             }
597             if (ctx->m_StickCalData[stick].axis[axis].sMin == 0xFFF) {
598                 ctx->m_StickCalData[stick].axis[axis].sMin = 0;
599             }
600         }
601     }
602 
603     if (input_mode == k_eSwitchInputReportIDs_SimpleControllerState) {
604         for (stick = 0; stick < 2; ++stick) {
605             for(axis = 0; axis < 2; ++axis) {
606                 ctx->m_StickExtents[stick].axis[axis].sMin = (Sint16)(SDL_MIN_SINT16 * 0.5f);
607                 ctx->m_StickExtents[stick].axis[axis].sMax = (Sint16)(SDL_MAX_SINT16 * 0.5f);
608             }
609         }
610     } else {
611         for (stick = 0; stick < 2; ++stick) {
612             for(axis = 0; axis < 2; ++axis) {
613                 ctx->m_StickExtents[stick].axis[axis].sMin = -(Sint16)(ctx->m_StickCalData[stick].axis[axis].sMin * 0.7f);
614                 ctx->m_StickExtents[stick].axis[axis].sMax = (Sint16)(ctx->m_StickCalData[stick].axis[axis].sMax * 0.7f);
615             }
616         }
617     }
618     return SDL_TRUE;
619 }
620 
fsel(float fComparand,float fValGE,float fLT)621 static float fsel(float fComparand, float fValGE, float fLT)
622 {
623     return fComparand >= 0 ? fValGE : fLT;
624 }
625 
RemapVal(float val,float A,float B,float C,float D)626 static float RemapVal(float val, float A, float B, float C, float D)
627 {
628     if (A == B) {
629         return fsel(val - B , D , C);
630     }
631     return C + (D - C) * (val - A) / (B - A);
632 }
633 
ApplyStickCalibrationCentered(SDL_DriverSwitch_Context * ctx,int nStick,int nAxis,Sint16 sRawValue,Sint16 sCenter)634 static Sint16 ApplyStickCalibrationCentered(SDL_DriverSwitch_Context *ctx, int nStick, int nAxis, Sint16 sRawValue, Sint16 sCenter)
635 {
636     sRawValue -= sCenter;
637 
638     if (sRawValue > ctx->m_StickExtents[nStick].axis[nAxis].sMax) {
639         ctx->m_StickExtents[nStick].axis[nAxis].sMax = sRawValue;
640     }
641     if (sRawValue < ctx->m_StickExtents[nStick].axis[nAxis].sMin) {
642         ctx->m_StickExtents[nStick].axis[nAxis].sMin = sRawValue;
643     }
644 
645     if (sRawValue > 0) {
646         return (Sint16)(RemapVal(sRawValue, 0, ctx->m_StickExtents[nStick].axis[nAxis].sMax, 0, SDL_MAX_SINT16));
647     } else {
648         return (Sint16)(RemapVal(sRawValue, ctx->m_StickExtents[nStick].axis[nAxis].sMin, 0, SDL_MIN_SINT16, 0));
649     }
650 }
651 
ApplyStickCalibration(SDL_DriverSwitch_Context * ctx,int nStick,int nAxis,Sint16 sRawValue)652 static Sint16 ApplyStickCalibration(SDL_DriverSwitch_Context *ctx, int nStick, int nAxis, Sint16 sRawValue)
653 {
654     return ApplyStickCalibrationCentered(ctx, nStick, nAxis, sRawValue, ctx->m_StickCalData[nStick].axis[nAxis].sCenter);
655 }
656 
SDL_GameControllerButtonReportingHintChanged(void * userdata,const char * name,const char * oldValue,const char * hint)657 static void SDLCALL SDL_GameControllerButtonReportingHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
658 {
659     SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)userdata;
660     ctx->m_bUseButtonLabels = SDL_GetStringBoolean(hint, SDL_TRUE);
661 }
662 
RemapButton(SDL_DriverSwitch_Context * ctx,Uint8 button)663 static Uint8 RemapButton(SDL_DriverSwitch_Context *ctx, Uint8 button)
664 {
665     if (!ctx->m_bUseButtonLabels) {
666         /* Use button positions */
667         if (ctx->m_bIsGameCube) {
668             switch (button) {
669             case SDL_CONTROLLER_BUTTON_B:
670                 return SDL_CONTROLLER_BUTTON_X;
671             case SDL_CONTROLLER_BUTTON_X:
672                 return SDL_CONTROLLER_BUTTON_B;
673             default:
674                 break;
675             }
676         } else {
677             switch (button) {
678             case SDL_CONTROLLER_BUTTON_A:
679                 return SDL_CONTROLLER_BUTTON_B;
680             case SDL_CONTROLLER_BUTTON_B:
681                 return SDL_CONTROLLER_BUTTON_A;
682             case SDL_CONTROLLER_BUTTON_X:
683                 return SDL_CONTROLLER_BUTTON_Y;
684             case SDL_CONTROLLER_BUTTON_Y:
685                 return SDL_CONTROLLER_BUTTON_X;
686             default:
687                 break;
688             }
689         }
690     }
691     return button;
692 }
693 
694 static SDL_bool
HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device * device)695 HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *device)
696 {
697     return HIDAPI_JoystickConnected(device, NULL, SDL_FALSE);
698 }
699 
700 static int
HIDAPI_DriverSwitch_GetDevicePlayerIndex(SDL_HIDAPI_Device * device,SDL_JoystickID instance_id)701 HIDAPI_DriverSwitch_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
702 {
703     return -1;
704 }
705 
706 static void
HIDAPI_DriverSwitch_SetDevicePlayerIndex(SDL_HIDAPI_Device * device,SDL_JoystickID instance_id,int player_index)707 HIDAPI_DriverSwitch_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
708 {
709 }
710 
711 static SDL_bool
HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)712 HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
713 {
714     SDL_DriverSwitch_Context *ctx;
715     Uint8 input_mode;
716 
717     ctx = (SDL_DriverSwitch_Context *)SDL_calloc(1, sizeof(*ctx));
718     if (!ctx) {
719         SDL_OutOfMemory();
720         goto error;
721     }
722     ctx->device = device;
723     device->context = ctx;
724 
725     device->dev = hid_open_path(device->path, 0);
726     if (!device->dev) {
727         SDL_SetError("Couldn't open %s", device->path);
728         goto error;
729     }
730 
731     /* Find out whether or not we can send output reports */
732     ctx->m_bInputOnly = SDL_IsJoystickNintendoSwitchProInputOnly(device->vendor_id, device->product_id);
733     if (!ctx->m_bInputOnly) {
734         ctx->m_bHasHomeLED = HasHomeLED(device->vendor_id, device->product_id);
735 
736         /* Initialize rumble data */
737         SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
738         SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]);
739 
740         /* Try setting up USB mode, and if that fails we're using Bluetooth */
741         if (!BTrySetupUSB(ctx)) {
742             ctx->m_bUsingBluetooth = SDL_TRUE;
743         }
744 
745         /* Determine the desired input mode (needed before loading stick calibration) */
746         if (ctx->m_bUsingBluetooth) {
747             input_mode = k_eSwitchInputReportIDs_SimpleControllerState;
748         } else {
749             input_mode = k_eSwitchInputReportIDs_FullControllerState;
750         }
751 
752         /* The official Nintendo Switch Pro Controller supports FullControllerState over bluetooth
753          * just fine. We really should use that, or else the epowerlevel code in
754          * HandleFullControllerState is completely pointless. We need full state if we want battery
755          * level and we only care about battery level over bluetooth anyway.
756          */
757         if (device->vendor_id == USB_VENDOR_NINTENDO &&
758             device->product_id == USB_PRODUCT_NINTENDO_SWITCH_PRO) {
759             input_mode = k_eSwitchInputReportIDs_FullControllerState;
760         }
761 
762         if (!LoadStickCalibration(ctx, input_mode)) {
763             SDL_SetError("Couldn't load stick calibration");
764             goto error;
765         }
766 
767         if (!SetVibrationEnabled(ctx, 1)) {
768             SDL_SetError("Couldn't enable vibration");
769             goto error;
770         }
771 
772         /* Set desired input mode */
773         if (!SetInputMode(ctx, input_mode)) {
774             SDL_SetError("Couldn't set input mode");
775             goto error;
776         }
777 
778         /* Start sending USB reports */
779         if (!ctx->m_bUsingBluetooth) {
780             /* ForceUSB doesn't generate an ACK, so don't wait for a reply */
781             if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_ForceUSB, NULL, 0, SDL_FALSE)) {
782                 SDL_SetError("Couldn't start USB reports");
783                 goto error;
784             }
785         }
786 
787         /* Set the LED state */
788         if (ctx->m_bHasHomeLED) {
789             SetHomeLED(ctx, 100);
790         }
791         SetSlotLED(ctx, (joystick->instance_id % 4));
792     }
793 
794     if (IsGameCubeFormFactor(device->vendor_id, device->product_id)) {
795         /* This is a controller shaped like a GameCube controller, with a large central A button */
796         ctx->m_bIsGameCube = SDL_TRUE;
797     }
798 
799     SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS,
800                         SDL_GameControllerButtonReportingHintChanged, ctx);
801 
802     /* Initialize the joystick capabilities */
803     joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
804     joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
805     joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
806 
807     return SDL_TRUE;
808 
809 error:
810     if (device->dev) {
811         hid_close(device->dev);
812         device->dev = NULL;
813     }
814     if (device->context) {
815         SDL_free(device->context);
816         device->context = NULL;
817     }
818     return SDL_FALSE;
819 }
820 
821 static int
HIDAPI_DriverSwitch_ActuallyRumbleJoystick(SDL_DriverSwitch_Context * ctx,Uint16 low_frequency_rumble,Uint16 high_frequency_rumble)822 HIDAPI_DriverSwitch_ActuallyRumbleJoystick(SDL_DriverSwitch_Context *ctx, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
823 {
824     /* Experimentally determined rumble values. These will only matter on some controllers as tested ones
825      * seem to disregard these and just use any non-zero rumble values as a binary flag for constant rumble
826      *
827      * More information about these values can be found here:
828      * https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md
829      */
830     const Uint16 k_usHighFreq = 0x0074;
831     const Uint8  k_ucHighFreqAmp = 0xBE;
832     const Uint8  k_ucLowFreq = 0x3D;
833     const Uint16 k_usLowFreqAmp = 0x806F;
834 
835     if (low_frequency_rumble) {
836         EncodeRumble(&ctx->m_RumblePacket.rumbleData[0], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp);
837     } else {
838         SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
839     }
840 
841     if (high_frequency_rumble) {
842         EncodeRumble(&ctx->m_RumblePacket.rumbleData[1], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp);
843     } else {
844         SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]);
845     }
846 
847     ctx->m_bRumbleActive = (low_frequency_rumble || high_frequency_rumble) ? SDL_TRUE : SDL_FALSE;
848 
849     if (!WriteRumble(ctx)) {
850         SDL_SetError("Couldn't send rumble packet");
851         return -1;
852     }
853     return 0;
854 }
855 
856 static int
HIDAPI_DriverSwitch_SendPendingRumble(SDL_DriverSwitch_Context * ctx)857 HIDAPI_DriverSwitch_SendPendingRumble(SDL_DriverSwitch_Context *ctx)
858 {
859     if ((SDL_GetTicks() - ctx->m_unRumbleSent) < RUMBLE_WRITE_FREQUENCY_MS) {
860         return 0;
861     }
862 
863     if (ctx->m_bRumblePending) {
864         Uint16 low_frequency_rumble = (Uint16)(ctx->m_unRumblePending >> 16);
865         Uint16 high_frequency_rumble = (Uint16)ctx->m_unRumblePending;
866 
867 #ifdef DEBUG_RUMBLE
868         SDL_Log("Sent pending rumble %d/%d\n", low_frequency_rumble, high_frequency_rumble);
869 #endif
870         ctx->m_bRumblePending = SDL_FALSE;
871         ctx->m_unRumblePending = 0;
872 
873         return HIDAPI_DriverSwitch_ActuallyRumbleJoystick(ctx, low_frequency_rumble, high_frequency_rumble);
874     }
875 
876     if (ctx->m_bRumbleZeroPending) {
877         ctx->m_bRumbleZeroPending = SDL_FALSE;
878 
879 #ifdef DEBUG_RUMBLE
880         SDL_Log("Sent pending zero rumble\n");
881 #endif
882         return HIDAPI_DriverSwitch_ActuallyRumbleJoystick(ctx, 0, 0);
883     }
884 
885     return 0;
886 }
887 
888 static int
HIDAPI_DriverSwitch_RumbleJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint16 low_frequency_rumble,Uint16 high_frequency_rumble)889 HIDAPI_DriverSwitch_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
890 {
891     SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
892 
893     if (ctx->m_bRumblePending) {
894         if (HIDAPI_DriverSwitch_SendPendingRumble(ctx) < 0) {
895             return -1;
896         }
897     }
898 
899     if (ctx->m_bUsingBluetooth && (SDL_GetTicks() - ctx->m_unRumbleSent) < RUMBLE_WRITE_FREQUENCY_MS) {
900         if (low_frequency_rumble || high_frequency_rumble) {
901             Uint32 unRumblePending = ((Uint32)low_frequency_rumble << 16) | high_frequency_rumble;
902 
903             /* Keep the highest rumble intensity in the given interval */
904             if (unRumblePending > ctx->m_unRumblePending) {
905                 ctx->m_unRumblePending = unRumblePending;
906             }
907             ctx->m_bRumblePending = SDL_TRUE;
908             ctx->m_bRumbleZeroPending = SDL_FALSE;
909         } else {
910             /* When rumble is complete, turn it off */
911             ctx->m_bRumbleZeroPending = SDL_TRUE;
912         }
913         return 0;
914     }
915 
916 #ifdef DEBUG_RUMBLE
917     SDL_Log("Sent rumble %d/%d\n", low_frequency_rumble, high_frequency_rumble);
918 #endif
919 
920     return HIDAPI_DriverSwitch_ActuallyRumbleJoystick(ctx, low_frequency_rumble, high_frequency_rumble);
921 }
922 
HandleInputOnlyControllerState(SDL_Joystick * joystick,SDL_DriverSwitch_Context * ctx,SwitchInputOnlyControllerStatePacket_t * packet)923 static void HandleInputOnlyControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchInputOnlyControllerStatePacket_t *packet)
924 {
925     Sint16 axis;
926 
927     if (packet->rgucButtons[0] != ctx->m_lastInputOnlyState.rgucButtons[0]) {
928         Uint8 data = packet->rgucButtons[0];
929         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_A), (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
930         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_B), (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
931         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_X), (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
932         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_Y), (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
933         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
934         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
935 
936         axis = (data & 0x40) ? 32767 : -32768;
937         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
938 
939         axis = (data & 0x80) ? 32767 : -32768;
940         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
941     }
942 
943     if (packet->rgucButtons[1] != ctx->m_lastInputOnlyState.rgucButtons[1]) {
944         Uint8 data = packet->rgucButtons[1];
945         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
946         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
947         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
948         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
949         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
950     }
951 
952     if (packet->ucStickHat != ctx->m_lastInputOnlyState.ucStickHat) {
953         SDL_bool dpad_up = SDL_FALSE;
954         SDL_bool dpad_down = SDL_FALSE;
955         SDL_bool dpad_left = SDL_FALSE;
956         SDL_bool dpad_right = SDL_FALSE;
957 
958         switch (packet->ucStickHat) {
959         case 0:
960             dpad_up = SDL_TRUE;
961             break;
962         case 1:
963             dpad_up = SDL_TRUE;
964             dpad_right = SDL_TRUE;
965             break;
966         case 2:
967             dpad_right = SDL_TRUE;
968             break;
969         case 3:
970             dpad_right = SDL_TRUE;
971             dpad_down = SDL_TRUE;
972             break;
973         case 4:
974             dpad_down = SDL_TRUE;
975             break;
976         case 5:
977             dpad_left = SDL_TRUE;
978             dpad_down = SDL_TRUE;
979             break;
980         case 6:
981             dpad_left = SDL_TRUE;
982             break;
983         case 7:
984             dpad_up = SDL_TRUE;
985             dpad_left = SDL_TRUE;
986             break;
987         default:
988             break;
989         }
990         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
991         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
992         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
993         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
994     }
995 
996     if (packet->rgucJoystickLeft[0] != ctx->m_lastInputOnlyState.rgucJoystickLeft[0]) {
997         axis = (Sint16)(RemapVal(packet->rgucJoystickLeft[0], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16));
998         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
999     }
1000 
1001     if (packet->rgucJoystickLeft[1] != ctx->m_lastInputOnlyState.rgucJoystickLeft[1]) {
1002         axis = (Sint16)(RemapVal(packet->rgucJoystickLeft[1], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16));
1003         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
1004     }
1005 
1006     if (packet->rgucJoystickRight[0] != ctx->m_lastInputOnlyState.rgucJoystickRight[0]) {
1007         axis = (Sint16)(RemapVal(packet->rgucJoystickRight[0], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16));
1008         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
1009     }
1010 
1011     if (packet->rgucJoystickRight[1] != ctx->m_lastInputOnlyState.rgucJoystickRight[1]) {
1012         axis = (Sint16)(RemapVal(packet->rgucJoystickRight[1], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16));
1013         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
1014     }
1015 
1016     ctx->m_lastInputOnlyState = *packet;
1017 }
1018 
HandleSimpleControllerState(SDL_Joystick * joystick,SDL_DriverSwitch_Context * ctx,SwitchSimpleStatePacket_t * packet)1019 static void HandleSimpleControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchSimpleStatePacket_t *packet)
1020 {
1021     /* 0x8000 is the neutral value for all joystick axes */
1022     const Uint16 usJoystickCenter = 0x8000;
1023     Sint16 axis;
1024 
1025     if (packet->rgucButtons[0] != ctx->m_lastSimpleState.rgucButtons[0]) {
1026         Uint8 data = packet->rgucButtons[0];
1027         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_A), (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
1028         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_B), (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
1029         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_X), (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
1030         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_Y), (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
1031         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
1032         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
1033 
1034         axis = (data & 0x40) ? 32767 : -32768;
1035         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
1036 
1037         axis = (data & 0x80) ? 32767 : -32768;
1038         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
1039     }
1040 
1041     if (packet->rgucButtons[1] != ctx->m_lastSimpleState.rgucButtons[1]) {
1042         Uint8 data = packet->rgucButtons[1];
1043         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
1044         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
1045         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
1046         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
1047         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
1048     }
1049 
1050     if (packet->ucStickHat != ctx->m_lastSimpleState.ucStickHat) {
1051         SDL_bool dpad_up = SDL_FALSE;
1052         SDL_bool dpad_down = SDL_FALSE;
1053         SDL_bool dpad_left = SDL_FALSE;
1054         SDL_bool dpad_right = SDL_FALSE;
1055 
1056         switch (packet->ucStickHat) {
1057         case 0:
1058             dpad_up = SDL_TRUE;
1059             break;
1060         case 1:
1061             dpad_up = SDL_TRUE;
1062             dpad_right = SDL_TRUE;
1063             break;
1064         case 2:
1065             dpad_right = SDL_TRUE;
1066             break;
1067         case 3:
1068             dpad_right = SDL_TRUE;
1069             dpad_down = SDL_TRUE;
1070             break;
1071         case 4:
1072             dpad_down = SDL_TRUE;
1073             break;
1074         case 5:
1075             dpad_left = SDL_TRUE;
1076             dpad_down = SDL_TRUE;
1077             break;
1078         case 6:
1079             dpad_left = SDL_TRUE;
1080             break;
1081         case 7:
1082             dpad_up = SDL_TRUE;
1083             dpad_left = SDL_TRUE;
1084             break;
1085         default:
1086             break;
1087         }
1088         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
1089         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
1090         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
1091         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
1092     }
1093 
1094     axis = ApplyStickCalibrationCentered(ctx, 0, 0, packet->sJoystickLeft[0], (Sint16)usJoystickCenter);
1095     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
1096 
1097     axis = ApplyStickCalibrationCentered(ctx, 0, 1, packet->sJoystickLeft[1], (Sint16)usJoystickCenter);
1098     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
1099 
1100     axis = ApplyStickCalibrationCentered(ctx, 1, 0, packet->sJoystickRight[0], (Sint16)usJoystickCenter);
1101     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
1102 
1103     axis = ApplyStickCalibrationCentered(ctx, 1, 1, packet->sJoystickRight[1], (Sint16)usJoystickCenter);
1104     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
1105 
1106     ctx->m_lastSimpleState = *packet;
1107 }
1108 
HandleFullControllerState(SDL_Joystick * joystick,SDL_DriverSwitch_Context * ctx,SwitchStatePacket_t * packet)1109 static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchStatePacket_t *packet)
1110 {
1111     Sint16 axis;
1112 
1113     if (packet->controllerState.rgucButtons[0] != ctx->m_lastFullState.controllerState.rgucButtons[0]) {
1114         Uint8 data = packet->controllerState.rgucButtons[0];
1115         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_A), (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
1116         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_B), (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
1117         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_X), (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
1118         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_Y), (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
1119         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED);
1120         axis = (data & 0x80) ? 32767 : -32768;
1121         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
1122     }
1123 
1124     if (packet->controllerState.rgucButtons[1] != ctx->m_lastFullState.controllerState.rgucButtons[1]) {
1125         Uint8 data = packet->controllerState.rgucButtons[1];
1126         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
1127         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
1128         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
1129         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
1130 
1131         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
1132     }
1133 
1134     if (packet->controllerState.rgucButtons[2] != ctx->m_lastFullState.controllerState.rgucButtons[2]) {
1135         Uint8 data = packet->controllerState.rgucButtons[2];
1136         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
1137         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
1138         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
1139         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
1140         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED);
1141         axis = (data & 0x80) ? 32767 : -32768;
1142         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
1143     }
1144 
1145     axis = packet->controllerState.rgucJoystickLeft[0] | ((packet->controllerState.rgucJoystickLeft[1] & 0xF) << 8);
1146     axis = ApplyStickCalibration(ctx, 0, 0, axis);
1147     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
1148 
1149     axis = ((packet->controllerState.rgucJoystickLeft[1] & 0xF0) >> 4) | (packet->controllerState.rgucJoystickLeft[2] << 4);
1150     axis = ApplyStickCalibration(ctx, 0, 1, axis);
1151     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~axis);
1152 
1153     axis = packet->controllerState.rgucJoystickRight[0] | ((packet->controllerState.rgucJoystickRight[1] & 0xF) << 8);
1154     axis = ApplyStickCalibration(ctx, 1, 0, axis);
1155     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
1156 
1157     axis = ((packet->controllerState.rgucJoystickRight[1] & 0xF0) >> 4) | (packet->controllerState.rgucJoystickRight[2] << 4);
1158     axis = ApplyStickCalibration(ctx, 1, 1, axis);
1159     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~axis);
1160 
1161     /* High nibble of battery/connection byte is battery level, low nibble is connection status
1162      * LSB of connection nibble is USB/Switch connection status
1163      */
1164     if (packet->controllerState.ucBatteryAndConnection & 0x1) {
1165         joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
1166     } else {
1167         /* LSB of the battery nibble is used to report charging.
1168          * The battery level is reported from 0(empty)-8(full)
1169          */
1170         int level = (packet->controllerState.ucBatteryAndConnection & 0xE0) >> 4;
1171         if (level == 0) {
1172             joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY;
1173         } else if (level <= 2) {
1174             joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW;
1175         } else if (level <= 6) {
1176             joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM;
1177         } else {
1178             joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
1179         }
1180     }
1181 
1182     ctx->m_lastFullState = *packet;
1183 }
1184 
1185 static SDL_bool
HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device * device)1186 HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device)
1187 {
1188     SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
1189     SDL_Joystick *joystick = NULL;
1190     int size;
1191 
1192     if (device->num_joysticks > 0) {
1193         joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
1194     }
1195     if (!joystick) {
1196         return SDL_FALSE;
1197     }
1198 
1199     while ((size = ReadInput(ctx)) > 0) {
1200         if (ctx->m_bInputOnly) {
1201             HandleInputOnlyControllerState(joystick, ctx, (SwitchInputOnlyControllerStatePacket_t *)&ctx->m_rgucReadBuffer[0]);
1202         } else {
1203             switch (ctx->m_rgucReadBuffer[0]) {
1204             case k_eSwitchInputReportIDs_SimpleControllerState:
1205                 HandleSimpleControllerState(joystick, ctx, (SwitchSimpleStatePacket_t *)&ctx->m_rgucReadBuffer[1]);
1206                 break;
1207             case k_eSwitchInputReportIDs_FullControllerState:
1208                 HandleFullControllerState(joystick, ctx, (SwitchStatePacket_t *)&ctx->m_rgucReadBuffer[1]);
1209                 break;
1210             default:
1211                 break;
1212             }
1213         }
1214     }
1215 
1216     if (ctx->m_bRumblePending || ctx->m_bRumbleZeroPending) {
1217         HIDAPI_DriverSwitch_SendPendingRumble(ctx);
1218     } else if (ctx->m_bRumbleActive &&
1219                SDL_TICKS_PASSED(SDL_GetTicks(), ctx->m_unRumbleSent + RUMBLE_REFRESH_FREQUENCY_MS)) {
1220 #ifdef DEBUG_RUMBLE
1221         SDL_Log("Sent continuing rumble\n");
1222 #endif
1223         WriteRumble(ctx);
1224     }
1225 
1226     if (size < 0) {
1227         /* Read error, device is disconnected */
1228         HIDAPI_JoystickDisconnected(device, joystick->instance_id, SDL_FALSE);
1229     }
1230     return (size >= 0);
1231 }
1232 
1233 static void
HIDAPI_DriverSwitch_CloseJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)1234 HIDAPI_DriverSwitch_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
1235 {
1236     SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
1237 
1238     if (!ctx->m_bInputOnly) {
1239         /* Restore simple input mode for other applications */
1240         SetInputMode(ctx, k_eSwitchInputReportIDs_SimpleControllerState);
1241     }
1242 
1243     SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS,
1244                         SDL_GameControllerButtonReportingHintChanged, ctx);
1245 
1246     hid_close(device->dev);
1247     device->dev = NULL;
1248 
1249     SDL_free(device->context);
1250     device->context = NULL;
1251 }
1252 
1253 static void
HIDAPI_DriverSwitch_FreeDevice(SDL_HIDAPI_Device * device)1254 HIDAPI_DriverSwitch_FreeDevice(SDL_HIDAPI_Device *device)
1255 {
1256 }
1257 
1258 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch =
1259 {
1260     SDL_HINT_JOYSTICK_HIDAPI_SWITCH,
1261     SDL_TRUE,
1262     HIDAPI_DriverSwitch_IsSupportedDevice,
1263     HIDAPI_DriverSwitch_GetDeviceName,
1264     HIDAPI_DriverSwitch_InitDevice,
1265     HIDAPI_DriverSwitch_GetDevicePlayerIndex,
1266     HIDAPI_DriverSwitch_SetDevicePlayerIndex,
1267     HIDAPI_DriverSwitch_UpdateDevice,
1268     HIDAPI_DriverSwitch_OpenJoystick,
1269     HIDAPI_DriverSwitch_RumbleJoystick,
1270     HIDAPI_DriverSwitch_CloseJoystick,
1271     HIDAPI_DriverSwitch_FreeDevice,
1272     NULL
1273 };
1274 
1275 #endif /* SDL_JOYSTICK_HIDAPI_SWITCH */
1276 
1277 #endif /* SDL_JOYSTICK_HIDAPI */
1278 
1279 /* vi: set ts=4 sw=4 expandtab: */
1280