1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2021 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 #include "../../SDL_internal.h"
22 
23 #ifdef SDL_JOYSTICK_HIDAPI
24 
25 #include "SDL_hints.h"
26 #include "SDL_events.h"
27 #include "SDL_joystick.h"
28 #include "SDL_gamecontroller.h"
29 #include "../SDL_sysjoystick.h"
30 #include "SDL_hidapijoystick_c.h"
31 #include "SDL_hidapi_rumble.h"
32 
33 
34 #ifdef SDL_JOYSTICK_HIDAPI_STADIA
35 
36 /* Define this if you want to log all packets from the controller */
37 /*#define DEBUG_STADIA_PROTOCOL*/
38 
39 enum
40 {
41     SDL_CONTROLLER_BUTTON_STADIA_SHARE = 15,
42     SDL_CONTROLLER_BUTTON_STADIA_GOOGLE_ASSISTANT,
43     SDL_CONTROLLER_NUM_STADIA_BUTTONS,
44 };
45 
46 typedef struct {
47     Uint8 last_state[USB_PACKET_LENGTH];
48 } SDL_DriverStadia_Context;
49 
50 
51 static SDL_bool
HIDAPI_DriverStadia_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)52 HIDAPI_DriverStadia_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)
53 {
54     return (type == SDL_CONTROLLER_TYPE_GOOGLE_STADIA) ? SDL_TRUE : SDL_FALSE;
55 }
56 
57 static const char *
HIDAPI_DriverStadia_GetDeviceName(Uint16 vendor_id,Uint16 product_id)58 HIDAPI_DriverStadia_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
59 {
60     return "Google Stadia Controller";
61 }
62 
63 static SDL_bool
HIDAPI_DriverStadia_InitDevice(SDL_HIDAPI_Device * device)64 HIDAPI_DriverStadia_InitDevice(SDL_HIDAPI_Device *device)
65 {
66     return HIDAPI_JoystickConnected(device, NULL);
67 }
68 
69 static int
HIDAPI_DriverStadia_GetDevicePlayerIndex(SDL_HIDAPI_Device * device,SDL_JoystickID instance_id)70 HIDAPI_DriverStadia_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
71 {
72     return -1;
73 }
74 
75 static void
HIDAPI_DriverStadia_SetDevicePlayerIndex(SDL_HIDAPI_Device * device,SDL_JoystickID instance_id,int player_index)76 HIDAPI_DriverStadia_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
77 {
78 }
79 
80 static SDL_bool
HIDAPI_DriverStadia_OpenJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)81 HIDAPI_DriverStadia_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
82 {
83     SDL_DriverStadia_Context *ctx;
84 
85     ctx = (SDL_DriverStadia_Context *)SDL_calloc(1, sizeof(*ctx));
86     if (!ctx) {
87         SDL_OutOfMemory();
88         return SDL_FALSE;
89     }
90 
91     device->dev = SDL_hid_open_path(device->path, 0);
92     if (!device->dev) {
93         SDL_SetError("Couldn't open %s", device->path);
94         SDL_free(ctx);
95         return SDL_FALSE;
96     }
97     device->context = ctx;
98 
99     /* Initialize the joystick capabilities */
100     joystick->nbuttons = SDL_CONTROLLER_NUM_STADIA_BUTTONS;
101     joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
102     joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
103 
104     return SDL_TRUE;
105 }
106 
107 static int
HIDAPI_DriverStadia_RumbleJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint16 low_frequency_rumble,Uint16 high_frequency_rumble)108 HIDAPI_DriverStadia_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
109 {
110     Uint8 rumble_packet[] = { 0x05, 0x00, 0x00, 0x00, 0x00 };
111 
112     rumble_packet[1] = (low_frequency_rumble & 0xFF);
113     rumble_packet[2] = (low_frequency_rumble >> 8);
114     rumble_packet[3] = (high_frequency_rumble & 0xFF);
115     rumble_packet[4] = (high_frequency_rumble >> 8);
116 
117     if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
118         return SDL_SetError("Couldn't send rumble packet");
119     }
120     return 0;
121 }
122 
123 static int
HIDAPI_DriverStadia_RumbleJoystickTriggers(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint16 left_rumble,Uint16 right_rumble)124 HIDAPI_DriverStadia_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
125 {
126     return SDL_Unsupported();
127 }
128 
129 static Uint32
HIDAPI_DriverStadia_GetJoystickCapabilities(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)130 HIDAPI_DriverStadia_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
131 {
132     return SDL_JOYCAP_RUMBLE;
133 }
134 
135 static int
HIDAPI_DriverStadia_SetJoystickLED(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint8 red,Uint8 green,Uint8 blue)136 HIDAPI_DriverStadia_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
137 {
138     return SDL_Unsupported();
139 }
140 
141 static int
HIDAPI_DriverStadia_SendJoystickEffect(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,const void * data,int size)142 HIDAPI_DriverStadia_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
143 {
144     return SDL_Unsupported();
145 }
146 
147 static int
HIDAPI_DriverStadia_SetJoystickSensorsEnabled(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,SDL_bool enabled)148 HIDAPI_DriverStadia_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
149 {
150     return SDL_Unsupported();
151 }
152 
153 static void
HIDAPI_DriverStadia_HandleStatePacket(SDL_Joystick * joystick,SDL_DriverStadia_Context * ctx,Uint8 * data,int size)154 HIDAPI_DriverStadia_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverStadia_Context *ctx, Uint8 *data, int size)
155 {
156     Sint16 axis;
157 
158 	// The format is the same but the original FW will send 10 bytes and January '21 FW update will send 11
159     if (size < 10 || data[0] != 0x03) {
160         /* We don't know how to handle this report */
161         return;
162     }
163 
164     if (ctx->last_state[1] != data[1]) {
165         SDL_bool dpad_up = SDL_FALSE;
166         SDL_bool dpad_down = SDL_FALSE;
167         SDL_bool dpad_left = SDL_FALSE;
168         SDL_bool dpad_right = SDL_FALSE;
169 
170         switch (data[1]) {
171         case 0:
172             dpad_up = SDL_TRUE;
173             break;
174         case 1:
175             dpad_up = SDL_TRUE;
176             dpad_right = SDL_TRUE;
177             break;
178         case 2:
179             dpad_right = SDL_TRUE;
180             break;
181         case 3:
182             dpad_right = SDL_TRUE;
183             dpad_down = SDL_TRUE;
184             break;
185         case 4:
186             dpad_down = SDL_TRUE;
187             break;
188         case 5:
189             dpad_left = SDL_TRUE;
190             dpad_down = SDL_TRUE;
191             break;
192         case 6:
193             dpad_left = SDL_TRUE;
194             break;
195         case 7:
196             dpad_up = SDL_TRUE;
197             dpad_left = SDL_TRUE;
198             break;
199         default:
200             break;
201         }
202         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
203         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
204         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
205         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
206     }
207 
208     if (ctx->last_state[2] != data[2]) {
209         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[2] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
210         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[2] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
211         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[2] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
212         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[2] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
213         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_STADIA_SHARE, (data[2] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
214         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_STADIA_GOOGLE_ASSISTANT, (data[2] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
215     }
216 
217     if (ctx->last_state[3] != data[3]) {
218         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[3] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
219         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[3] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
220         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[3] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
221         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[3] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
222         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[3] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
223         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[3] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
224         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[3] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
225     }
226 
227 #define READ_STICK_AXIS(offset) \
228     (data[offset] == 0x80 ? 0 : \
229     (Sint16)HIDAPI_RemapVal((float)((int)data[offset] - 0x80), 0x01 - 0x80, 0xff - 0x80, SDL_MIN_SINT16, SDL_MAX_SINT16))
230     {
231         axis = READ_STICK_AXIS(4);
232         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
233         axis = READ_STICK_AXIS(5);
234         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
235         axis = READ_STICK_AXIS(6);
236         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
237         axis = READ_STICK_AXIS(7);
238         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
239     }
240 #undef READ_STICK_AXIS
241 
242 #define READ_TRIGGER_AXIS(offset) \
243     (Sint16)(((int)data[offset] * 257) - 32768)
244     {
245         axis = READ_TRIGGER_AXIS(8);
246         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
247         axis = READ_TRIGGER_AXIS(9);
248         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
249     }
250 #undef READ_TRIGGER_AXIS
251 
252     SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
253 }
254 
255 static SDL_bool
HIDAPI_DriverStadia_UpdateDevice(SDL_HIDAPI_Device * device)256 HIDAPI_DriverStadia_UpdateDevice(SDL_HIDAPI_Device *device)
257 {
258     SDL_DriverStadia_Context *ctx = (SDL_DriverStadia_Context *)device->context;
259     SDL_Joystick *joystick = NULL;
260     Uint8 data[USB_PACKET_LENGTH];
261     int size = 0;
262 
263     if (device->num_joysticks > 0) {
264         joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
265     }
266     if (!joystick) {
267         return SDL_FALSE;
268     }
269 
270     while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
271 #ifdef DEBUG_STADIA_PROTOCOL
272         HIDAPI_DumpPacket("Google Stadia packet: size = %d", data, size);
273 #endif
274         HIDAPI_DriverStadia_HandleStatePacket(joystick, ctx, data, size);
275     }
276 
277     if (size < 0) {
278         /* Read error, device is disconnected */
279         HIDAPI_JoystickDisconnected(device, joystick->instance_id);
280     }
281     return (size >= 0);
282 }
283 
284 static void
HIDAPI_DriverStadia_CloseJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)285 HIDAPI_DriverStadia_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
286 {
287     SDL_LockMutex(device->dev_lock);
288     {
289         if (device->dev) {
290             SDL_hid_close(device->dev);
291             device->dev = NULL;
292         }
293 
294         SDL_free(device->context);
295         device->context = NULL;
296     }
297     SDL_UnlockMutex(device->dev_lock);
298 }
299 
300 static void
HIDAPI_DriverStadia_FreeDevice(SDL_HIDAPI_Device * device)301 HIDAPI_DriverStadia_FreeDevice(SDL_HIDAPI_Device *device)
302 {
303 }
304 
305 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverStadia =
306 {
307     SDL_HINT_JOYSTICK_HIDAPI_STADIA,
308     SDL_TRUE,
309     SDL_TRUE,
310     HIDAPI_DriverStadia_IsSupportedDevice,
311     HIDAPI_DriverStadia_GetDeviceName,
312     HIDAPI_DriverStadia_InitDevice,
313     HIDAPI_DriverStadia_GetDevicePlayerIndex,
314     HIDAPI_DriverStadia_SetDevicePlayerIndex,
315     HIDAPI_DriverStadia_UpdateDevice,
316     HIDAPI_DriverStadia_OpenJoystick,
317     HIDAPI_DriverStadia_RumbleJoystick,
318     HIDAPI_DriverStadia_RumbleJoystickTriggers,
319     HIDAPI_DriverStadia_GetJoystickCapabilities,
320     HIDAPI_DriverStadia_SetJoystickLED,
321     HIDAPI_DriverStadia_SendJoystickEffect,
322     HIDAPI_DriverStadia_SetJoystickSensorsEnabled,
323     HIDAPI_DriverStadia_CloseJoystick,
324     HIDAPI_DriverStadia_FreeDevice,
325 };
326 
327 #endif /* SDL_JOYSTICK_HIDAPI_STADIA */
328 
329 #endif /* SDL_JOYSTICK_HIDAPI */
330 
331 /* vi: set ts=4 sw=4 expandtab: */
332